【发布时间】:2021-11-17 21:50:36
【问题描述】:
我正在尝试使用来自scripy.optimize 的curve_fit 将a*x**b+c 形式的幂律拟合到某些数据点。
这是 MWE:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def func_powerlaw(x, m, c, c0):
return c0 + x**m * c
x = np.array([1.05, 1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55])
y = np.array([1.26, 1.24, 1.2, 1.17, 1.1, 1.01, 0.95, 0.84, 0.75, 0.71, 0.63])
dy = np.array([0.078]*11)
fig, (a1) = plt.subplots(ncols=1,figsize=(10,10))
a1.errorbar(x, y, yerr = dy, ls = '', marker='o')
popt, pcov = curve_fit(func_powerlaw, x, y, sigma = dy, p0 = [0.3, 1, 1], bounds=[(0.1, -2, -2), (0.9, 10, 2)], absolute_sigma=False, maxfev=10000, method = 'trf')
perr=np.sqrt(np.diag(pcov))
xp = np.linspace(x[0],x[-1], 100)
a1.plot(xp, func_powerlaw(xp, *popt), lw=3, zorder = 1, c = 'b')
print(popt, perr)
输出:[0.35609897 3.24929422 -2.] [0.47034928 3.9030258 3.90965249]
对于所有三个参数,误差都大于值估计本身。从经验来看,这不可能是正确的,因为这条线非常适合数据点。
即使我没有设置任何界限和/或初始猜测,值也会改变,但错误仍然太高。
唯一需要的边界是0.1<=m<=0.9。
我究竟做错了什么?
非常感谢任何帮助!
【问题讨论】:
-
不确定性
dy表示任何值y_i +/- dy都与观察到的数据y兼容。观测数据的大误差会导致拟合参数的大误差。尝试以下操作:for y in np.random.uniform(y - dy, y + dy, size=(25, len(y))): ...,然后对每个随机采样的y(在其不确定性边界内采样)执行拟合,但没有表明拟合过程存在错误(sigma)。然后记录生成的参数估计值 (popt) 并查看np.mean(popts), np.std(popts)。第二个值应与您的匹配值相匹配。 -
用盐的海洋来发表我的意见,因为我从来没有做过这种事情,但它可能会过度拟合吗?
-
@a_guest 按照这个逻辑,不应该完全删除 sigma 以获得更好的拟合吗?因为似乎恰恰相反。
-
@chess_lover_6 我也尝试过
lmfit,据我所知,它是curve_fit 的包装器,它打印了 χ^2 值。它们很糟糕,甚至不接近 1。所以我认为这不是因为过度拟合。 -
@George 首先,将
sigma与absolute_sigma=False一起使用的值与absolute_sigma=False一起使用没有任何效果,因为如文档中所述,如果False(默认),只有 sigma 值的相对大小很重要。尽管如此,这似乎与您手头的问题无关,因为当您完全删除sigma时,这仍然会导致perr很大。如果我理解正确,这是您的实际问题:生成的曲线非常适合数据点(例如从绘图或 R2 分数判断),但是报告的perr非常大。
标签: python numpy scipy curve-fitting scipy-optimize