双高斯峰Python拟合失败求助:结果异常、pcov值为无穷
Python双高斯峰拟合失败排查
我尝试用Python对数据进行双高斯峰拟合,但结果明显错误。参考了多种写法都无法成功拟合,尝试均值理论也没有改善。用LabVIEW能完成拟合,但Python实现失败,希望排查错误。怀疑拟合参数popt或边界设置存在问题,且发现pcov值为无穷,这十分反常。
原代码
import numpy as np data = np.loadtxt('C:/Users/user/Desktop/sheet1 test.txt', delimiter=',') print(data.shape) print(data.dtype) import matplotlib.pyplot as plt x = data[:, 0] y = data[:, 1] #fitting function from scipy.optimize import curve_fit #individual peak def gauss(x,a,w,p,c): #C = 0 fun_val = 0 + ((a/1.253*w)*np.exp(-2*((x-p)**2/w**2))) return fun_val #double peak def d_gauss(x, a1, p1,a2, p2): #w1 = 0.049 #w2 = 0.029 #c1 = c2 = 0 fun_val1 = 0 + ((a1/1.253*0.049)*np.exp(-2*((x-p1)**2/0.049**2))) fun_val2 = 0 + ((a2/1.253*0.029)*np.exp(-2*((x-p2)**2/0.029**2))) return fun_val1 + fun_val2 initial_gauss_peak = [1.43896,186.097, 1.4743,393.263] #bnd = ( (lower limit ) , ( upper limit ) ) bnd = ((1.4,10 ,1.45,100) , (1.5 ,1000 ,1.52,5000) ) #fitting popt,pcov = curve_fit(d_gauss,x,y, p0 = initial_gauss_peak, bounds = bnd) yfit = gauss(x, popt[0], popt[1] ,popt[2], popt[3]) yfit1 = gauss(x, popt[0], 0.049 ,popt[1], 0) yfit2 = gauss(x, popt[2], 0.029 ,popt[3], 0) plt.plot(x,y ,'o', label = 'data') plt.plot(x,yfit1 , label = 'peak 1' , color = 'b') plt.plot(x,yfit2 , label = 'peak 2' , color = 'c') plt.plot(x ,yfit ,linewidth = 2, label = 'fit' , color = 'k') plt.legend() #plt.plot(x, y) plt.xlabel('X Axis') plt.ylabel('Y Axis') plt.title('Scatter Plot') plt.show()
拟合结果图

问题排查与修正建议
核心错误点
- 拟合与绘图参数不匹配:
d_gauss的参数是a1,p1,a2,p2,但绘图时yfit调用gauss函数传入的参数顺序是popt[0], popt[1], popt[2], popt[3],而gauss需要的是a,w,p,c,完全对应错误,导致总拟合曲线完全偏离。 - 固定峰宽可能不符合数据实际:强行固定
w1=0.049、w2=0.029,如果实际数据的峰宽和这个值偏差较大,会导致拟合无法收敛,出现pcov无穷的情况。 - 边界设置逻辑混乱:初始参数
p1的初始值是186,但边界下限设为10、上限1000,范围过大,容易导致拟合算法迷失最优解。
修正后的代码示例
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 加载数据 data = np.loadtxt('C:/Users/user/Desktop/sheet1 test.txt', delimiter=',') x = data[:, 0] y = data[:, 1] # 标准单个高斯峰函数(包含基线) def gauss(x, amp, wid, pos, base): return base + (amp / (wid * np.sqrt(2 * np.pi))) * np.exp(-((x - pos)**2) / (2 * wid**2)) # 双高斯峰函数 def double_gauss(x, amp1, wid1, pos1, amp2, wid2, pos2, base): return gauss(x, amp1, wid1, pos1, 0) + gauss(x, amp2, wid2, pos2, 0) + base # 初始参数:基于LabVIEW结果或数据估计 init_params = [1.44, 0.049, 186.1, 1.47, 0.029, 393.3, 0] # 合理设置边界:根据数据范围限制参数 bounds = ( [1.0, 0.01, 180, 1.0, 0.01, 390, -0.1], [2.0, 0.1, 190, 2.0, 0.05, 400, 0.1] ) # 执行拟合 popt, pcov = curve_fit(double_gauss, x, y, p0=init_params, bounds=bounds) # 计算各类拟合曲线 y_total = double_gauss(x, *popt) y_peak1 = gauss(x, popt[0], popt[1], popt[2], 0) y_peak2 = gauss(x, popt[3], popt[4], popt[5], 0) # 绘图 plt.figure(figsize=(10, 6)) plt.plot(x, y, 'o', label='原始数据') plt.plot(x, y_peak1, label='峰1拟合', color='b') plt.plot(x, y_peak2, label='峰2拟合', color='c') plt.plot(x, y_total, linewidth=2, label='总拟合曲线', color='k') plt.xlabel('X轴') plt.ylabel('Y轴') plt.title('双高斯峰拟合结果') plt.legend() plt.show() # 输出拟合参数 print("拟合参数:", popt)
关键优化点
- 统一函数逻辑:使用标准高斯分布公式,避免自定义系数带来的误差,同时加入基线参数,适配实际数据的偏移情况。
- 参数全可调:放开峰宽参数,让拟合算法自动寻找最优峰宽,避免强行固定带来的拟合偏差。
- 参数匹配与边界收紧:确保初始参数、边界、拟合函数的参数顺序完全一致,同时根据数据实际范围收紧边界,帮助算法快速收敛。
内容的提问来源于stack exchange,提问作者Weiyan
相关产品推荐
相关产品推荐

