Mam trochę problemów z dopasowaniem krzywej do niektórych danych, ale nie mogę wykombinować, gdzie idę źle.Wykładnicze dopasowanie krzywej zaniku w numpy i scipy
W przeszłości Zrobiłem to z numpy.linalg.lstsq dla funkcji wykładniczej i scipy.optimize.curve_fit dla funkcji sigmoidowych. Tym razem chciałem stworzyć skrypt, który pozwoliłby mi określić różne funkcje, określić parametry i przetestować ich dopasowanie względem danych. Robiąc to zauważyłem, że Scipy leastsq
i Numpy lstsq
wydają się zapewniać różne odpowiedzi dla tego samego zestawu danych i tej samej funkcji. Funkcja jest po prostu y = e^(l*x)
i jest ograniczona tak, że y=1
w x=0
.
Linia trendu programu Excel zgadza się z wynikiem Numpy lstsq
, ale ponieważ Scipy leastsq
może pełnić jakąkolwiek funkcję, dobrze byłoby ustalić, na czym polega problem.
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()
Edycja - informacja dodatkowa
MWE powyżej zawiera małą próbkę zbiorze danych. Podczas dopasowywania rzeczywistych danych krzywa przedstawia R^2 0,82, podczas gdy krzywa numpy.linalg.lstsq, która jest taka sama, jak obliczona przez Excel, ma wartość R^2 wynoszącą 0,41. .
Dzięki @Jaime - świetna odpowiedź!Niestety moja znajomość matematyki nie jest tak wielka; czy ktoś pisze lub źle [patrz także edytuj powyżej], czy są one po prostu zasadniczo różne ...? Jakie są implikacje dla innych funkcji, na przykład, gdybym chciał przetestować dopasowanie krzywej Sigmoid lub Gompertz do tych samych danych? – StacyR
@StacyR Nie mam wiedzy, aby właściwie odpowiedzieć na twoje pytanie, ale jestem całkiem pewny, że dopasowanie wykładniczej, jak to zrobiłeś z 'np.linalg.lstsq' jest po prostu szybką i niecałkowitą sztuczką, która nie jest obliczana błędy prawidłowo. Jest tu pewna dyskusja (trudna do naśladowania) tutaj: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html Jeśli nie chcesz zanurzyć się naprawdę głęboko w te rzeczy, poszedłbym z metodą scipy na wszystko: to powinien dawać lepsze dopasowania, a twoje wyniki będą spójne dla wszystkich funkcji. – Jaime
dzięki jeszcze raz! Zrobiłem trochę więcej badań na ten temat i, jak wspomniałeś, odkryłem, że metoda 'np.linalg.lstsq' nadmiernie obciąża błędy y przy niskich wartościach x. Udostępniony przeze mnie link i kilka innych zasobów, które znalazłem, pozwoliły mi wyprowadzić jedną inną metodę analityczną (rzeczą, która sprawia, że jest to trudne jest ograniczenie - wszystkie książki opisują metodę dla y = a * e^b * x raczej niż y = e^b * x), jednak powoduje to również gorszą krzywą dopasowania niż iteracyjne 'scipy.optimize.leastsq'. – StacyR