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.