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 sipolyfit
toma una muy mala decisión para la gran y , la "división por- | y |" factor lo compensará, lo que polyfit
favorecerá los valores pequeños.
Esto podría aliviarse dando a cada entrada un "peso" proporcional a y . polyfit
admite mínimos cuadrados ponderados a través del w
argumento 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_fit
para 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_fit
podamos 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.
y
sea 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_fit
a partirscipy.optimize
. Por ejemplo, si desea ajustar una función exponencial (de la documentación ):Y luego, si quieres trazar, puedes hacer:
(Nota: la
*
frentepopt
al trazar ampliará los términos en ela
,b
yc
quefunc
. Espera)fuente
a
,b
yc
?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%timeit
magia 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 loop
x = 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
,y
o 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:
A
a través de intercept (ln(A)
)B
ví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
lmfit
al resolver ambos problemas.Dado
Código
Enfoque 1 -
lmfit
ModeloAjustar 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