Para ajustar y = A + B log x , 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 o ajuste y = Ae Bx , tome o logaritmo de ambos os lados, obtendo log y = log A + Bx . Então ajuste (log y ) contra x .
Observe que o ajuste (log y ) como se fosse linear enfatizará pequenos valores de y , causando um desvio grande para y grande . Isto é porque polyfit
(regressão linear) funciona através da minimização Σ i (Δ Y ) 2 = S i ( Y i - Ŷ i ) 2 . Quando Y i = log y i , os resíduos Δ Y i = Δ (log y i ) ≈ Δ y i / | e eu | Então, mesmo quepolyfit
toma uma decisão muito ruim para y grande , o "dividir por | | y |" fator compensará isso, polyfit
favorecendo pequenos valores.
Isso pode ser aliviado, atribuindo a cada entrada um "peso" proporcional a y . polyfit
suporta mínimos ponderados por meio do w
argumento de palavra - chave.
>>> 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)
Observe que o Excel, o LibreOffice e a maioria das calculadoras científicas geralmente usam a fórmula não ponderada (tendenciosa) para as linhas de regressão / tendência exponencial. Se você deseja que seus resultados sejam compatíveis com essas plataformas, não inclua os pesos, mesmo que eles ofereçam melhores resultados.
Agora, se você puder usar o scipy, poderá usar scipy.optimize.curve_fit
para ajustar qualquer modelo sem transformações.
Para y = A + B log x, o resultado é o mesmo que o método de transformação:
>>> 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 = Ae Bx , no entanto, podemos obter um melhor ajuste, pois calcula Δ (log y ) diretamente. Mas precisamos fornecer um palpite de inicialização para curve_fit
alcançar o mínimo local desejado.
>>> 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
pequenas são artificialmente ponderadas . É melhor definir a função (linear, não a transformação do log) e usar um ajustador ou minimizador de curvas.Você também pode caber um conjunto de dados para qualquer função você gosta de usar
curve_fit
a partirscipy.optimize
. Por exemplo, se você deseja ajustar uma função exponencial (da documentação ):E então, se você deseja traçar, você pode fazer:
(Nota: o
*
na frente depopt
quando você traçar irá expandir os termos para oa
,b
ec
quefunc
. Está esperando)fonte
a
,b
ec
?Eu estava tendo algum problema com isso, então deixe-me ser muito explícito para que pessoas como eu possam entender.
Digamos que temos um arquivo de dados ou algo assim
o resultado é: a = 0.849195983017, b = -1.18101681765, c = 2.24061176543, d = 0.816643894816
fonte
y = [np.exp(i) for i in x]
é muito lento; uma razão pela qual o numpy foi criado foi para que você pudesse escrevery=np.exp(x)
. Além disso, com essa substituição, você pode se livrar da sua seção de força brutal. Em ipython, há a%timeit
magia da qualIn [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)
deve permitir que você se livre da compreensão lenta da lista.Bem, eu acho que você sempre pode usar:
Modificando ligeiramente a resposta do IanVS :
Isso resulta no seguinte gráfico:
fonte
Aqui está uma opção de linearização de dados simples que usa ferramentas do scikit learn .
Dado
Código
Ajustar dados exponenciais
Ajustar dados de log
Detalhes
Etapas gerais
x
,y
ou ambos)np.exp()
) e ajustada aos dados originaisSupondo que nossos dados sigam uma tendência exponencial, uma equação geral + pode ser:
Podemos linearizar a última equação (por exemplo, y = interceptar + inclinação * x) tomando o log :
Dada uma equação linearizada ++ e os parâmetros de regressão, poderíamos calcular:
A
via intercept (ln(A)
)B
via declive (B
)Resumo das técnicas de linearização
+ Nota: as funções exponenciais linearizadas funcionam melhor quando o ruído é pequeno e C = 0. Use com cuidado.
++ Nota: enquanto a alteração de dados x ajuda a linearizar dados exponenciais , a alteração de dados ajuda a linearizar dados de log .
fonte
Demonstramos recursos de
lmfit
ao resolver os dois problemas.Dado
Código
Abordagem 1 -
lmfit
ModeloAjustar dados exponenciais
Abordagem 2 - Modelo personalizado
Ajustar dados de log
Detalhes
Você pode determinar os parâmetros inferidos do objeto regressor. Exemplo:
Nota: a
ExponentialModel()
seguir, uma função de decaimento , que aceita dois parâmetros, um dos quais é negativo.Veja também
ExponentialGaussianModel()
, que aceita mais parâmetros .Instale a biblioteca via
> pip install lmfit
.fonte
A Wolfram possui uma solução de formulário fechado para ajustar um exponencial . Eles também têm soluções semelhantes para ajustar uma lei logarítmica e de energia .
Eu achei que isso funcionava melhor do que o curve_fit de scipy Aqui está um exemplo:
fonte