Python SciPy 中的指数曲线拟合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21420792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exponential curve fitting in SciPy
提问by drastega
I have two NumPy arrays xand y. When I try to fit my data using exponential function and curve_fit(SciPy) with this simple code
我有两个 NumPy 数组x和y. 当我尝试使用指数函数和curve_fit(SciPy)用这个简单的代码拟合我的数据时
#!/usr/bin/env python
from pylab import *
from scipy.optimize import curve_fit
x = np.array([399.75, 989.25, 1578.75, 2168.25, 2757.75, 3347.25, 3936.75, 4526.25, 5115.75, 5705.25])
y = np.array([109,62,39,13,10,4,2,0,1,2])
def func(x, a, b, c, d):
return a*np.exp(b-c*x)+d
popt, pcov = curve_fit(func, x, y)
I get wrong coefficients popt
我得到错误的系数 popt
[a,b,c,d] = [1., 1., 1., 24.19999988]
What is the problem?
问题是什么?
采纳答案by Warren Weckesser
First comment: since a*exp(b - c*x) = (a*exp(b))*exp(-c*x) = A*exp(-c*x), aor bis redundant. I'll drop band use:
第一条评论:因为a*exp(b - c*x) = (a*exp(b))*exp(-c*x) = A*exp(-c*x), aorb是多余的。我会放弃b并使用:
def func(x, a, c, d):
return a*np.exp(-c*x)+d
That isn't the main issue. The problem is simply that curve_fitfails to converge to a solution to this problem when you use the default initial guess (which is all 1s). Check pcov; you'll see that it is inf. This is not surprising, because if cis 1, most of the values of exp(-c*x)underflow to 0:
这不是主要问题。问题很简单,curve_fit当您使用默认的初始猜测(全为 1)时,无法收敛到该问题的解决方案。检查pcov; 你会看到它是inf。这并不奇怪,因为如果c是 1,则exp(-c*x)下溢的大部分值都为 0:
In [32]: np.exp(-x)
Out[32]:
array([ 2.45912644e-174, 0.00000000e+000, 0.00000000e+000,
0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
0.00000000e+000])
This suggests that cshould be small. A better initial guess is, say, p0 = (1, 1e-6, 1). Then I get:
这表明c应该很小。一个更好的初始猜测是,比如说,p0 = (1, 1e-6, 1)。然后我得到:
In [36]: popt, pcov = curve_fit(func, x, y, p0=(1, 1e-6, 1))
In [37]: popt
Out[37]: array([ 1.63561656e+02, 9.71142196e-04, -1.16854450e+00])
This looks reasonable:
这看起来很合理:
In [42]: xx = np.linspace(300, 6000, 1000)
In [43]: yy = func(xx, *popt)
In [44]: plot(x, y, 'ko')
Out[44]: [<matplotlib.lines.Line2D at 0x41c5ad0>]
In [45]: plot(xx, yy)
Out[45]: [<matplotlib.lines.Line2D at 0x41c5c10>]


回答by three_pineapples
Firstly I would recommend modifying your equation to a*np.exp(-c*(x-b))+d, otherwise the exponential will always be centered on x=0which may not always be the case.
You also need to specify reasonable initial conditions (the 4th argument to curve_fitspecifies initial conditions for [a,b,c,d]).
首先,我建议将您的方程修改为a*np.exp(-c*(x-b))+d,否则指数将始终以x=0这种情况为中心。您还需要指定合理的初始条件(第四参数curve_fit指定为初始条件[a,b,c,d])。
This code fits nicely:
这段代码很适合:
from pylab import *
from scipy.optimize import curve_fit
x = np.array([399.75, 989.25, 1578.75, 2168.25, 2757.75, 3347.25, 3936.75, 4526.25, 5115.75, 5705.25])
y = np.array([109,62,39,13,10,4,2,0,1,2])
def func(x, a, b, c, d):
return a*np.exp(-c*(x-b))+d
popt, pcov = curve_fit(func, x, y, [100,400,0.001,0])
print popt
plot(x,y)
x=linspace(400,6000,10000)
plot(x,func(x,*popt))
show()

