Sto avendo un po 'di problemi con l'adattamento di una curva ad alcuni dati, ma non riesco a capire dove sto andando male.Curva di decadimento esponenziale in numpy e scipy
In passato ho fatto questo con numpy.linalg.lstsq per le funzioni esponenziali e scipy.optimize.curve_fit per le funzioni sigma. Questa volta ho voluto creare uno script che mi permettesse di specificare varie funzioni, determinare i parametri e testarne la compatibilità con i dati. Mentre facevo questo, ho notato che Scipy e Numpy lstsq
sembrano fornire risposte diverse per lo stesso insieme di dati e la stessa funzione. La funzione è semplicemente y = e^(l*x)
ed è vincolata in modo tale che y=1
a x=0
.
La linea di tendenza di Excel è d'accordo con il risultato di Numpy lstsq
, ma siccome Scipy leastsq
è in grado di svolgere qualsiasi funzione, sarebbe opportuno capire qual è il problema.
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()
Modifica - ulteriori informazioni
La MWE sopra comprende un piccolo campione del set di dati. Quando si adattano i dati effettivi la curva scipy.optimize.curve_fit presenta un R^2 di 0,82, mentre la curva numpy.linalg.lstsq, che è la stessa calcolata da Excel, ha un R^2 di 0,41 .
Grazie @Jaime - ottima risposta!Sfortunatamente la mia conoscenza matematica non è così grande; è uno scritto o sbagliato [vedi anche modifica sopra], o sono fondamentalmente diversi ...? Quali sono le implicazioni per altre funzioni, ad esempio, se volessi testare l'adattamento di una curva Sigmoid o Gompertz agli stessi dati? – StacyR
@StacyR Non ho le conoscenze per rispondere correttamente alla tua domanda, ma sono abbastanza sicuro che montare un esponenziale come hai fatto con 'np.linalg.lstsq' è solo un trucco veloce e non truccato che non calcola errori correttamente. C'è qualche discussione (difficile da seguire) qui: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html Se non vuoi immergerti davvero in questa roba, sceglierei il metodo di scipy per tutto: dovrebbe dare migliori misure e i risultati saranno coerenti per tutte le funzioni. – Jaime
grazie ancora! Ho fatto qualche ricerca in più su questo argomento e, come lei ha accennato, ho scoperto che il metodo 'np.linalg.lstsq' esalta eccessivamente gli errori y a valori di x bassi. Il link che hai condiviso e alcune altre risorse che ho trovato mi hanno permesso di ricavare un altro metodo analitico (la cosa che rende complicato il vincolo --- tutti i libri descrivono il metodo per y = a * e^b * x piuttosto di y = e^b * x), tuttavia, questo produce anche una curva di adattamento peggiore rispetto al ripetitivo 'scipy.optimize.leastsq'. – StacyR