Para el montaje y = Un registro + Bx, acaba de encajar 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 el montaje y = AeBx, tomar el logaritmo de ambos lados da log y = log A + Bx. Ajuste (log y) contra x.
Nota que ajuste (log y) como si es lineal hará hincapié en valores pequeños de y, causando desviación grande para gran y. Esto se debe a polyfit
(regresión lineal) funciona minimizando Σ i (Δ Y) = Σ i (Y i − Ŷi) . Cuando Yi = log yi, los residuos Δ Yi = Δ (log yi) ≈ Δ yi/| yi |. Entonces, incluso si polyfit
toma una decisión muy mala para la gran y, la "división-por-y |" factor lo compensará, causando que polyfit
favorezca valores pequeños.
Esto se puede aliviar dando a cada entrada un "peso" proporcional a y. polyfit
admite ponderados mínimos cuadrados mediante el argumento de palabra clave w
.
>>> 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 ponderado (sesgada) para las líneas de regresión/tendencia exponencial. Si desea que sus resultados sean compatibles con estas plataformas, no incluya los pesos, incluso si proporciona mejores resultados.
Ahora, si se puede usar scipy, podría utilizar scipy.optimize.curve_fit
para adaptarse a cualquier modelo sin transformaciones.
Para y = A + B registro 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)
Para y = AeBx Sin embargo, podemos obtener un mejor ajuste ya que calcula Δ (log y) directamente. Pero tenemos que proporcionar una conjetura de inicialización para que curve_fit
pueda 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.
Gracias, eso es perfecto, pero ¿cómo puedo encontrar la base de los logaritmos que se adapte a la mejor? –
@Tomas: Por lo general, el registro natural, pero cualquier registro funciona. Solo recuerda que si usas la base K, entonces la ecuación se convierte en y = A * K^(Bx). – kennytm
Entonces, ¿la calidad del accesorio (por ejemplo, R2) no depende de la base del logaritmo? Gracias una vez más, las respuestas son perfectas, muy útiles, le daré un punto tan pronto como tenga suficiente reputación. –