J'ai quelques difficultés à ajuster une courbe à certaines données, mais je n'arrive pas à déterminer où je me trompe.Ajustement de la courbe de décroissance exponentielle en numpy et scipy
Dans le passé, je l'ai fait cela avec numpy.linalg.lstsq pour les fonctions exponentielles et scipy.optimize.curve_fit pour les fonctions sigmoïde. Cette fois-ci, j'ai souhaité créer un script qui me permettrait de spécifier différentes fonctions, de déterminer les paramètres et de tester leur adéquation aux données. En faisant cela, j'ai remarqué que Scipy leastsq
et Numpy lstsq
semblent fournir des réponses différentes pour le même ensemble de données et la même fonction. La fonction est simplement y = e^(l*x)
et est contrainte de telle sorte que y=1
à x=0
.
La ligne de tendance Excel est en accord avec le résultat Numpy lstsq
, mais comme Scipy leastsq
peut prendre n'importe quelle fonction, il serait bon de déterminer quel est le problème.
import scipy.optimize as optimize
import numpy as np
import matplotlib.pyplot as plt
## Sampled data
x = np.array([0, 14, 37, 975, 2013, 2095, 2147])
y = np.array([1.0, 0.764317544, 0.647136491, 0.070803763, 0.003630962, 0.001485394, 0.000495131])
# function
fp = lambda p, x: np.exp(p*x)
# error function
e = lambda p, x, y: (fp(p, x) - y)
# using scipy least squares
l1, s = optimize.leastsq(e, -0.004, args=(x,y))
print l1
# [-0.0132281]
# using numpy least squares
l2 = np.linalg.lstsq(np.vstack([x, np.zeros(len(x))]).T,np.log(y))[0][0]
print l2
# -0.00313461628963 (same answer as Excel trend line)
# smooth x for plotting
x_ = np.arange(0, x[-1], 0.2)
plt.figure()
plt.plot(x, y, 'rx', x_, fp(l1, x_), 'b-', x_, fp(l2, x_), 'g-')
plt.show()
Edition - informations supplémentaires
Le MWE ci-dessus comprend un petit échantillon de l'ensemble de données. Lors de l'ajustement des données réelles, la courbe scipy.optimize.curve_fit présente un R^2 de 0,82, tandis que la courbe numpy.linalg.lstsq, qui est la même que celle calculée par Excel, a un R^2 de 0,41 .
Merci @Jaime - bonne réponse!Malheureusement, mes connaissances en mathématiques ne sont pas si bonnes. est-ce que l'on écrit ou mal [voir aussi l'édition ci-dessus], ou sont-ils simplement fondamentalement différents ...? Quelles sont les implications pour d'autres fonctions, par exemple, si je voulais tester l'ajustement d'une courbe Sigmoïde ou Gompertz aux mêmes données? – StacyR
@StacyR Je n'ai pas les connaissances pour répondre correctement à votre question, mais je suis à peu près sûr que l'ajustement d'une exponentielle comme vous l'avez fait avec 'np.linalg.lstsq' est juste une astuce quick'n'dirty qui ne calcule pas erreurs correctement. Il y a une discussion (dure pour moi à suivre) ici: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html Si vous ne voulez pas plonger vraiment profondément dans ce genre de choses, j'irais avec la méthode de scipy pour tout: devrait donner de meilleurs ajustements, et vos résultats seront cohérents pour toutes les fonctions. – Jaime
merci encore! J'ai fait d'autres recherches à ce sujet et, comme vous l'avez mentionné, j'ai trouvé que la méthode 'np.linalg.lstsq' pondère excessivement les erreurs y à de faibles valeurs x. Le lien que vous avez partagé, et quelques autres ressources que j'ai trouvées, m'ont permis de dériver une autre méthode analytique (la chose qui la rend difficile est la contrainte --- tous les livres décrivent la méthode pour y = a * e^b * x plutôt que y = e^b * x), cependant, cela produit également une courbe moins bonne que l'itérative 'scipy.optimize.leastsq'. – StacyR