使用scipy.minimize拟合三高斯模型遇参数传递错误求助
解决scipy.minimize拟合多高斯函数的参数传递问题
嘿,我来帮你搞定这个问题!你遇到的错误核心是目标函数的参数结构和scipy.minimize的调用方式不匹配,还有几个其他小问题需要调整,咱们一步步来:
错误原因分析
- 错误的函数调用方式:你在
minimize里传的是sumGauss(x, y),这会直接执行这个函数并把结果传给minimize,但minimize需要的是一个可调用的函数对象,而不是函数执行后的结果。这直接导致sumGauss执行时args为空,所以解包9个参数时失败。 - 目标函数参数顺序错误:scipy.minimize要求目标函数的第一个参数是待优化的参数数组,额外的数据集(比如x、y)需要通过
args参数传递,而不是反过来。 - 目标函数返回值不对:你当前返回的是残差数组,但minimize默认需要一个标量值来最小化——我们通常会最小化残差的平方和(这样才是标准的拟合误差)。
- 错误使用了Rosenbrock函数的导数/海森矩阵:
rosen_der和rosen_hess是专门给Rosenbrock测试函数用的,和你的高斯拟合完全不相关,不能直接用在这儿。
修正后的完整代码
import numpy from matplotlib import pyplot from scipy.optimize import minimize # 实验数据 x = numpy.arange(0, 55) y = [-0.00058032, -0.00063992, -0.00057869, -0.00058395, -0.00053528, -0.0002694, -0.0003716, -0.000284, 0.00104651, 0.00209935, 0.00360213, 0.00502779, 0.00625538, 0.00715873, 0.00753231, 0.00712235, 0.00689089, 0.0061677, 0.00544124, 0.00478251, 0.00487787, 0.00415067, 0.00368579, 0.00370327, 0.00323007, 0.0029862, 0.00250529, 0.00219493, 0.00212242, 0.00209026, 0.0020827, 0.00204044, 0.00218628, 0.00236552, 0.00245056, 0.00282404, 0.0031072, 0.00332862, 0.00351655, 0.00367349, 0.00387923, 0.00395812, 0.00388796, 0.00379902, 0.00369458, 0.00350222, 0.00337815, 0.0032241, 0.00306897, 0.00294152, 0.00276761, 0.00257586, 0.00231613, 0.00211727, 0.00190347] # 目标函数:计算残差的平方和(最小化这个值) def sumGauss(params, x, y): # params是待优化的参数数组,解包成各个高斯参数 m1, m2, m3, s1, s2, s3, k1, k2, k3 = params # 计算三个高斯的和 gauss_sum = (k1 * numpy.exp(-(x - m1)**2 / (2 * s1**2)) + k2 * numpy.exp(-(x - m2)**2 / (2 * s2**2)) + k3 * numpy.exp(-(x - m3)**2 / (2 * s3**2))) # 返回残差的平方和(这是我们要最小化的标量) return numpy.sum((gauss_sum - y)**2) # 初始猜测值 initial_values = [15, 29, 43, 1, 1, 1, 0.007, 0.002, 0.004] # 调整了初始的k值,更接近数据的峰值,有助于拟合收敛 # 调用minimize:第一个参数是目标函数,第二个是初始值,args传递额外的x和y res = minimize(sumGauss, initial_values, args=(x, y), method='L-BFGS-B', # 换一个更适合曲线拟合的方法,不需要自定义jac/hess options={'gtol': 1e-8, 'disp': True}) # 打印拟合结果 print("拟合得到的参数:") print(res.x) # 绘制拟合结果 fit_y = (res.x[6] * numpy.exp(-(x - res.x[0])**2 / (2 * res.x[3]**2)) + res.x[7] * numpy.exp(-(x - res.x[1])**2 / (2 * res.x[4]**2)) + res.x[8] * numpy.exp(-(x - res.x[2])**2 / (2 * res.x[5]**2))) pyplot.scatter(x, y, label='实验数据') pyplot.plot(x, fit_y, 'r-', label='拟合曲线') pyplot.legend() pyplot.show()
关键调整点说明
- 目标函数参数顺序:把待优化的
params放在第一个位置,x和y作为后续参数,通过minimize的args=(x,y)传递给目标函数。 - 返回残差平方和:这样minimize才有一个标量值可以最小化,符合拟合的需求。
- 移除错误的jac/hess参数:我们用了
L-BFGS-B方法,它会自动计算近似的导数,不需要手动指定(而且你之前用的Rosen函数的导数完全不匹配)。 - 优化初始猜测值:调整了
k1/k2/k3的初始值,更接近数据的实际峰值,能帮助拟合算法更快收敛。
运行结果说明
运行后你会看到拟合的参数输出,同时会弹出图像显示实验数据和拟合曲线的对比。如果拟合效果还不够理想,可以尝试调整初始值,或者换用其他minimize方法(比如'Nelder-Mead')。
内容的提问来源于stack exchange,提问作者Dusan Kojic
相关产品推荐
相关产品推荐

