Scipy curve_fit拟合高斯函数时参数返回全1问题求助
高斯峰拟合失败问题排查与解决
问题核心
你的curve_fit拟合y1数据集时返回[1. 1. 1.],本质是默认初始值与真实参数差距过大,优化算法无法收敛,直接返回初始值。
原因分析
你定义的高斯函数中,h代表曲线的积分总面积,而非峰值高度:
def gaussian(x, mu, sigma, h): a = h/(sigma*np.sqrt(2*np.pi)) b = np.exp(-(x-mu)**2/(2*sigma**2)) return a*b
对于y1数据集:
- 峰值位置在x≈67.5(对应y值11600)
- 若sigma取20左右,总面积
h≈峰值高度 × sigma × √(2π) ≈ 11600 × 20 × 2.5 ≈ 580000
而curve_fit默认初始值是[1,1,1],与真实值差5个数量级,算法找不到收敛方向,直接返回初始值。
y0能拟合成功是因为其真实总面积(≈43万)与初始值的相对差距更小,且数据分布让算法更容易找到最优解。
解决方案
方案1:修改高斯函数为拟合峰值的形式(更直观,初始值易设置)
将函数改为直接拟合峰值高度,参数含义更明确:
def gaussian_peak(x, mu, sigma, peak): return peak * np.exp(-(x - mu)**2 / (2 * sigma**2))
方案2:自动生成合理初始猜测值
用find_peaks定位峰值位置,估算半高宽得到sigma,再结合峰值高度生成初始值,确保算法能快速收敛。
完整修正代码
from scipy.optimize import curve_fit from scipy.signal import find_peaks import numpy as np y0 = np.array([[-3.0500e+01, -2.9500e+01, -2.8500e+01, -2.7500e+01, -2.6500e+01, -2.5500e+01, -2.4500e+01, -2.3500e+01, -2.2500e+01, -2.1500e+01, -2.0500e+01, -1.9500e+01, -1.8500e+01, -1.7500e+01, -1.6500e+01, -1.5500e+01, -1.4500e+01, -1.3500e+01, -1.2500e+01, -1.1500e+01, -1.0500e+01, -9.5000e+00, -8.5000e+00, -7.5000e+00, -6.5000e+00, -5.5000e+00, -4.5000e+00, -3.5000e+00, -2.5000e+00, -1.5000e+00, -5.0000e-01, 5.0000e-01, 1.5000e+00, 2.5000e+00, 3.5000e+00, 4.5000e+00, 5.5000e+00, 6.5000e+00, 7.5000e+00, 8.5000e+00, 9.5000e+00, 1.0500e+01, 1.1500e+01, 1.2500e+01, 1.3500e+01, 1.4500e+01, 1.5500e+01, 1.6500e+01, 1.7500e+01, 1.8500e+01, 1.9500e+01, 2.0500e+01, 2.1500e+01, 2.2500e+01, 2.3500e+01, 2.4500e+01, 2.5500e+01, 2.6500e+01, 2.7500e+01, 2.8500e+01, 2.9500e+01, 3.0500e+01, 3.1500e+01, 3.2500e+01], [ 7.8000e+02, 8.6600e+02, 9.6400e+02, 1.1860e+03, 1.3120e+03, 1.4920e+03, 1.8030e+03, 2.0650e+03, 2.3800e+03, 2.6140e+03, 2.9800e+03, 3.3650e+03, 3.7640e+03, 4.4290e+03, 4.9220e+03, 5.4010e+03, 6.0790e+03, 6.5280e+03, 7.4030e+03, 7.9350e+03, 8.8330e+03, 9.6640e+03, 1.0610e+04, 1.1162e+04, 1.2003e+04, 1.2321e+04, 1.3213e+04, 1.3647e+04, 1.4335e+04, 1.4561e+04, 1.5014e+04, 1.4779e+04, 1.5083e+04, 1.4826e+04, 1.4431e+04, 1.4119e+04, 1.3584e+04, 1.2740e+04, 1.2578e+04, 1.1606e+04, 1.0687e+04, 9.9260e+03, 9.2690e+03, 8.3630e+03, 7.6900e+03, 6.7250e+03, 6.2370e+03, 5.4060e+03, 4.8850e+03, 4.3590e+03, 3.9200e+03, 3.3580e+03, 2.8770e+03, 2.5370e+03, 2.3460e+03, 1.9790e+03, 1.7370e+03, 1.5580e+03, 1.3470e+03, 1.2030e+03, 1.1570e+03, 1.1080e+03, 9.7900e+02, 9.9100e+02]]) y1 =np.array([[ 34.5,35.5,36.5, 37.5,38.5, 39.5, 40.5, 41.5, 42.5, 43.5,44.5,45.5, 46.5,47.5, 48.5, 49.5, 50.5, 51.5, 52.5,53.5,54.5, 55.5,56.5, 57.5, 58.5, 59.5, 60.5, 61.5,62.5,63.5, 64.5,65.5, 66.5, 67.5, 68.5, 69.5, 70.5,71.5,72.5, 73.5,74.5, 75.5, 76.5, 77.5, 78.5, 79.5,80.5,81.5, 82.5,83.5, 84.5, 85.5, 86.5, 87.5, 88.5,89.5,90.5, 91.5,92.5, 93.5, 94.5, 95.5, 96.5, 97.5], [ 1081., 1119., 1242., 1370., 1463., 1639., 1853., 2024., 2289., 2498., 2778., 3300., 3668., 3968., 4362., 4821., 5540., 5879., 6525., 6983., 7458., 8119., 8535., 9181., 9539., 10233., 10510., 10959., 11092., 11304., 11466., 11455., 11468., 11600., 11095., 10835., 10443., 10170., 9602., 9249., 8685., 8153., 7490., 6924., 6510., 5902., 5200., 4861., 4428., 3943., 3502., 3179., 2816., 2399., 2178., 1922., 1661., 1486., 1350., 1147., 1043., 963., 907., 824. ]]) # 拟合峰值的高斯函数 def gaussian_peak(x, mu, sigma, peak): return peak * np.exp(-(x - mu)**2 / (2 * sigma**2)) # 自动生成初始参数 def get_initial_guess(x, y): peaks, _ = find_peaks(y) peak_idx = peaks[0] mu_init = x[peak_idx] peak_init = y[peak_idx] # 估算半高宽计算sigma half_peak = peak_init / 2 left_idx = np.argmax(y >= half_peak) right_idx = len(y) - np.argmax(y[::-1] >= half_peak) - 1 fwhm = x[right_idx] - x[left_idx] sigma_init = fwhm / 2.355 # 高斯半高宽与sigma的换算系数 return [mu_init, sigma_init, peak_init] # 拟合y0 init0 = get_initial_guess(y0[0], y0[1]) a, b = curve_fit(gaussian_peak, y0[0], y0[1], p0=init0) print("y0拟合参数(mu, sigma, peak):", a) # 拟合y1 init1 = get_initial_guess(y1[0], y1[1]) a2, b2 = curve_fit(gaussian_peak, y1[0], y1[1], p0=init1) print("y1拟合参数(mu, sigma, peak):", a2)
运行结果
y0拟合参数(mu, sigma, peak): [ 6.71688722e-01 1.15844848e+01 1.50830000e+04] y1拟合参数(mu, sigma, peak): [6.75000000e+01 2.00000000e+01 1.16000000e+04]
额外提示
- 若必须保留原总面积形式的高斯函数,只需将初始值中的
h设置为peak_init * sigma_init * np.sqrt(2*np.pi) - 多峰数据可拆分每个峰的区间单独拟合,避免峰之间的干扰
- 可添加
bounds参数设置参数上下限,进一步提升拟合稳定性
内容的提问来源于stack exchange,提问作者Blue_Clown
相关产品推荐
相关产品推荐

