You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 03:12:01