Para ajustar y = A + B log x , simplemente ajuste y contra (log x ).
>>> x = numpy.array([1, 7, 20, 50, 79])
>>> y = numpy.array([10, 19, 30, 35, 51])
>>> numpy.polyfit(numpy.log(x), y, 1)
array([ 8.46295607, 6.61867463])
# y ≈ 8.46 log(x) + 6.62
Para ajustar y = Ae Bx , tomar el logaritmo de ambos lados da log y = log A + Bx . Entonces ajuste (log y ) contra x .
Tenga en cuenta que el ajuste (log y ) como si fuera lineal enfatizará los valores pequeños de y , causando una gran desviación para y grande . Esto se debe a que polyfit(regresión lineal) funciona minimizando ∑ i (Δ Y ) 2 = ∑ i ( Y i - Ŷ i ) 2 . Cuando Y i = log y i , los residuos Δ Y i = Δ (log y i ) ≈ Δ y i / | y yo |. Entonces, incluso sipolyfittoma una muy mala decisión para la gran y , la "división por- | y |" factor lo compensará, lo que polyfitfavorecerá los valores pequeños.
Esto podría aliviarse dando a cada entrada un "peso" proporcional a y . polyfitadmite mínimos cuadrados ponderados a través del wargumento de palabra clave.
>>> x = numpy.array([10, 19, 30, 35, 51])
>>> y = numpy.array([1, 7, 20, 50, 79])
>>> numpy.polyfit(x, numpy.log(y), 1)
array([ 0.10502711, -0.40116352])
# y ≈ exp(-0.401) * exp(0.105 * x) = 0.670 * exp(0.105 * x)
# (^ biased towards small values)
>>> numpy.polyfit(x, numpy.log(y), 1, w=numpy.sqrt(y))
array([ 0.06009446, 1.41648096])
# y ≈ exp(1.42) * exp(0.0601 * x) = 4.12 * exp(0.0601 * x)
# (^ not so biased)
Tenga en cuenta que Excel, LibreOffice y la mayoría de las calculadoras científicas suelen utilizar la fórmula no ponderada (sesgada) para las líneas de tendencia / regresión exponencial. Si desea que sus resultados sean compatibles con estas plataformas, no incluya los pesos incluso si proporciona mejores resultados.
Ahora, si puede usar scipy, podría usarlo scipy.optimize.curve_fitpara ajustar cualquier modelo sin transformaciones.
Para y = A + B log x el resultado es el mismo que el método de transformación:
>>> x = numpy.array([1, 7, 20, 50, 79])
>>> y = numpy.array([10, 19, 30, 35, 51])
>>> scipy.optimize.curve_fit(lambda t,a,b: a+b*numpy.log(t), x, y)
(array([ 6.61867467, 8.46295606]),
array([[ 28.15948002, -7.89609542],
[ -7.89609542, 2.9857172 ]]))
# y ≈ 6.62 + 8.46 log(x)
Sin embargo, para y = Ae Bx , podemos obtener un mejor ajuste ya que calcula Δ (log y ) directamente. Pero necesitamos proporcionar una conjetura de inicialización para que curve_fitpodamos alcanzar el mínimo local deseado.
>>> x = numpy.array([10, 19, 30, 35, 51])
>>> y = numpy.array([1, 7, 20, 50, 79])
>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y)
(array([ 5.60728326e-21, 9.99993501e-01]),
array([[ 4.14809412e-27, -1.45078961e-08],
[ -1.45078961e-08, 5.07411462e+10]]))
# oops, definitely wrong.
>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y, p0=(4, 0.1))
(array([ 4.88003249, 0.05531256]),
array([[ 1.01261314e+01, -4.31940132e-02],
[ -4.31940132e-02, 1.91188656e-04]]))
# y ≈ 4.88 exp(0.0553 x). much better.

ysea pequeño se sobreponderarán artificialmente. Es mejor definir la función (lineal, no la transformación logarítmica) y usar un ajustador o minimizador de curvas.También puede adaptarse a un conjunto de datos a cualquier función te gusta usar
curve_fita partirscipy.optimize. Por ejemplo, si desea ajustar una función exponencial (de la documentación ):Y luego, si quieres trazar, puedes hacer:
(Nota: la
*frentepoptal trazar ampliará los términos en ela,bycquefunc. Espera)fuente
a,byc?Estaba teniendo algunos problemas con esto, así que déjame ser muy explícito para que novatos como yo puedan entender.
Digamos que tenemos un archivo de datos o algo así
el resultado es: a = 0.849195983017, b = -1.18101681765, c = 2.24061176543, d = 0.816643894816
fuente
y = [np.exp(i) for i in x]es muy lento; Una de las razones por las que se creó Numpy fue para poder escribiry=np.exp(x). Además, con ese reemplazo, puedes deshacerte de tu sección de fuerza brutal. En ipython, existe la%timeitmagia de la cualIn [27]: %timeit ylist=[exp(i) for i in x] 10000 loops, best of 3: 172 us per loop In [28]: %timeit yarr=exp(x) 100000 loops, best of 3: 2.85 us per loopx = np.array(x, dtype=float)debería permitirle deshacerse de la comprensión lenta de la lista.Bueno, supongo que siempre puedes usar:
Modificando ligeramente la respuesta de IanVS :
Esto da como resultado el siguiente gráfico:
fuente
Aquí hay una opción de linealización en datos simples que utiliza herramientas de scikit learn .
Dado
Código
Ajustar datos exponenciales
Ajustar datos de registro
Detalles
Pasos generales
x,yo ambos)np.exp()) y ajústela a los datos originalesSuponiendo que nuestros datos siguen una tendencia exponencial, una ecuación general + puede ser:
Podemos linealizar la última ecuación (por ejemplo, y = intercepción + pendiente * x) tomando el registro :
Dada una ecuación linealizada ++ y los parámetros de regresión, podríamos calcular:
Aa través de intercept (ln(A))Bvía pendiente (B)Resumen de técnicas de linealización
+ Nota: la linealización de las funciones exponenciales funciona mejor cuando el ruido es pequeño y C = 0. Usar con precaución.
++ Nota: mientras que la modificación de datos x ayuda a linealizar datos exponenciales , la modificación de datos y ayuda a linealizar datos de registro .
fuente
Demostramos características de
lmfital resolver ambos problemas.Dado
Código
Enfoque 1 -
lmfitModeloAjustar datos exponenciales
Enfoque 2 - Modelo personalizado
Ajustar datos de registro
Detalles
Puede determinar los parámetros inferidos del objeto regresor. Ejemplo:
Nota:
ExponentialModel()sigue una función de disminución , que acepta dos parámetros, uno de los cuales es negativo.Ver también
ExponentialGaussianModel(), que acepta más parámetros. .Instalar la biblioteca a través de
> pip install lmfit.fuente
Wolfram tiene una solución de forma cerrada para ajustar una exponencial . También tienen soluciones similares para ajustar una ley logarítmica y de poder .
Encontré que esto funciona mejor que scipy's curve_fit. Aquí hay un ejemplo:
fuente