为什么我的optimize.leastsq不工作?
我正在尝试将一个函数拟合到我的数据上。我有两个不同的坐标轴,x轴表示身高,y轴表示体重。通过肉眼观察,我可以看到数据大致呈现出一个平方根函数的形状,并且在体重为10附近趋于饱和。以下是我正在做的事情:
from scipy import optimize
fitfunc = lambda p, x: np.sqrt(p[0]* x + p[1]) +p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y
sort_idx = np.argsort(height)
height = height[sort_idx]
weight = weight[sort_idx]
p0 = [0.1, 0.2, 0.3] # initial values
p1, success = optimize.leastsq(errfunc, p0, args=(height, weight), maxfev=10000)
无论我把p0设置成什么值,输出的结果总是p1等于p0。
我哪里做错了呢?
你觉得如果数据趋于饱和,使用不同的函数会更好吗?
提前谢谢你!
3 个回答
2
谢谢你的帮助。我想我知道问题出在哪里了。某种原因下,平方根(sqrt)变成了负数,这就导致了错误。当我把变量调整一下,确保它不能是负数时,程序就开始正常运行了,也就是说:
p[0]* np.sqrt(x + np.abs(p[1]))
虽然这不是完全一样的,但对我来说有效。我应该早点想到这一点。再次感谢你。
2
这段话不是直接回答你的问题,但根据你提供的数据,我在这里没有遇到任何问题,可以进行拟合:
import sys
from scipy import optimize
import numpy as np
from matplotlib import pyplot as plt
height=np.array([34.75625407,126.90646855,369.02594015,321.33822843,100.89398254,119.73654933,421.4400502,98.09051003,72.61433571,626.54970675,45.97802204,741.65476066,39.13568217,67.21666378,58.44445182,31.9950751,32.74788721,168.3256637,149.57003524,1058.41323859])
weight=np.array([4.375,3.95833333,9.16666667,8.125,3.75,8.4375,7.91666667,7.5,5.,10.,6.25,7.625,5.,6.25,10.,3.75,4.375,6.66666667,6.25,8.28125])
fitfunc = lambda p, x: np.sqrt(p[0]* x + p[1]) +p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y
pp = [0.2, 0.3, 0.4]
sort_idx = np.argsort(height)
height = height[sort_idx]
weight = weight[sort_idx]
p0 = [0.2, 0.2, 0.3] # initial values
result = optimize.leastsq(errfunc, p0, args=(height, weight), maxfev=10000, full_output=1)
p1 = result[0]
print result[3]
plt.plot(height, weight, 'o')
plt.plot(height, fitfunc(p1, height), '-')
plt.show()
你可以像我在上面的代码中那样,设置 full_output=1
,然后打印出你得到的信息。注意,我的 success
值实际上是2,而不是4。所以这里有些奇怪的差别。因为我们应该使用相同的数据,所以你的scipy设置可能有问题。或者,你没有展示完整的问题,可能在其他地方出了问题。
从图中来看,我确实看到这些值分布得很散,所以无论如何都很难进行拟合(实际上,我是不建议这样做的!)。
3
你可能把体重和身高搞反了,如果它们是某个人群的体重和身高。除此之外,你的代码运行得非常好:
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
fitfunc = lambda p, x: np.sqrt(p[0]* x + p[1]) +p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y
height = np.random.normal(loc=1.70, scale=.15, size=(100))
bmi = np.random.normal(loc=20, scale=2, size=(100))
weight = bmi * height**2
sort_idx = np.argsort(weight)
height = height[sort_idx]
weight = weight[sort_idx]
p0 = [0.1, 0.2, 0.3] # initial values
p1, success = optimize.leastsq(errfunc, p0, args=(weight, height), maxfev=10000)
plt.plot(weight, height, 'o')
plt.plot(weight, fitfunc(p1, weight), '-')
plt.xlabel('weight')
plt.ylabel('height')
plt.show()
>>> p1
array([ 0.01625167, -0.32844465, 0.9256349 ])
代码有时会给出一些警告,比如:
RuntimeWarning: invalid value encountered in sqrt
fitfunc = lambda p, x: np.sqrt(p[0]* x + p[1]) +p[2] # Target function
你可能想重新定义你的 fitfunc
和 errfunc
,可以这样做:
fitfunc2 = lambda p, y: ((y - p[2])**2 - p[1]) / p[0] # Target function
errfunc2 = lambda p, x, y: fitfunc2(p, y) - x
然后执行:
p2, success2 = optimize.leastsq(errfunc2, p0, args=(weight, height), maxfev=10000)
绘制这个和之前的图会得到稍微不同但可以比较的结果: