我一直在尝试使用scipy.optimize.curve_fit将函数拟合到某些数据:
from __future__ import (print_function,
division,
unicode_literals,
absolute_import)
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as mpl
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
y = np.array([20.8, 20.9, 22.9, 25.2, 26.9, 28.3, 29.5, 30.7, 31.8, 32.9, 34.0, 35.3, 36.4, 37.5, 38.6, 39.6, 40.6, 41.6, 42.5, 43.2, 44.2, 45.0, 45.8, 46.5, 47.3, 48.0, 48.6, 49.2, 49.8, 50.4])
def f(x, a, b, c):
return a/(1+b*x**c)
popt, pcov = curve_fit(f, x, y)
print(popt, np.sqrt(np.diag(pcov)), sep='\n')
但总会出现错误:
RuntimeWarning: divide by zero encountered in power
return a/(1+b*x**c)
也许有人可以帮我避免它? 任何帮助将非常感激。干杯!
答案 0 :(得分:5)
好吧,两个有用的技巧。
1,将0
中的x
替换为一些非常小的数字,例如1e-8
(不要笑,R
中的核心包实际上是这是由his name shall not be spoken
撰写的,人们一直都在使用它。)
实际上我根本没有得到你的RuntimeWarning
。我正在运行scipy
0.12.0
和numpy
1.7.1
。也许这取决于版本。
但我们会非常不合适:
In [41]: popt, pcov
Out[41]: (array([ 3.90107143e+01, -3.08698757e+07, -1.52971609e+02]), inf)
因此,技巧2,我们定义f
函数,而不是优化g
函数:
In [38]: def g(x, a, b, c):
....: return b/a*x**c+1/a
....:
In [39]: curve_fit(g, x, 1/y) #Better fit
Out[39]:
(array([ 19.76748582, -0.14499508, 0.44206688]),
array([[ 0.29043958, 0.00899521, 0.01650935],
[ 0.00899521, 0.00036082, 0.00070345],
[ 0.01650935, 0.00070345, 0.00140253]]))
我们现在可以使用生成的参数向量作为起始向量来优化f()
。由于curve_fit
是非线性最小二乘法,参数优化g()
不一定是参数优化f()
,但希望它会接近。协方差矩阵当然是非常不同的。
In [78]: curve_fit(f, x, y, p0=curve_fit(g, x, 1/y)[0]) #Alternative Fit
Out[78]:
(array([ 18.0480446 , -0.22881647, 0.31200106]),
array([[ 1.14928169, 0.03741604, 0.03897652],
[ 0.03741604, 0.00128511, 0.00136315],
[ 0.03897652, 0.00136315, 0.00145614]]))
结果的比较:
现在结果非常好。
答案 1 :(得分:4)
您的x值从0开始。如果由于某种原因,参数c
在计算过程中为负,那么您将评估0上升为负指数,即除以零:对于{{1}我们有
p>0