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

如何将多高斯拟合函数funcn传入scipy curve_fit并设置bounds

多高斯曲线拟合的泛化实现与curve_fit调用方案

问题背景

已知X为多个高斯函数的和,现有双高斯拟合代码(当Cluster=2时可正常运行):

双高斯函数定义:

def func2(x, a1, a2, m1, m2, s1, s2):
    return a1*np.exp(-((x-m1)/s1)**2) + a2*np.exp(-((x-m2)/s2)**2)

配合curve_fit的调用代码:

# 设置参数范围
AmpMin = 0.01
AmpMax = 1000
CenMin = min(x)
CenMax = max(x)
WidMin = 0.1
WidMax = 100

popt, pcov = curve_fit(func2, x, y, 
                       bounds=([AmpMin,AmpMin, CenMin,CenMin, WidMin,WidMin],
                               [AmpMax,AmpMax, CenMax,CenMax, WidMax,WidMax]))

现在需要将上述代码泛化为支持指定Cluster数量的多高斯拟合,但原有的funcn写法无法直接传入curve_fit:

def fun1(x,a,m,s):
    return a*np.exp(-((x-m)/s)**2)

def funcn(x, as[],ms[],ss[]):
    accum = fun1(x,as[0],ms[0],ss[0])
    for i in range(1,len(as)):
        accum = accum + fun1(x,as[i],ms[i],ss[i])
    return accum

需解决:如何调整funcn使其适配scipy.optimize.curve_fit,并正确设置bounds参数?


解决方案

核心问题说明

scipy.optimize.curve_fit要求拟合函数的所有待优化参数必须是扁平的位置参数,不能直接传入列表类型的参数,因此需要重构多高斯函数的参数结构。

1. 重构多高斯拟合函数

将所有高斯分量的振幅(a)、中心(m)、宽度(s)作为扁平的位置参数传入,在函数内部按每组3个参数(对应一个高斯分量)拆分处理:

import numpy as np
from scipy.optimize import curve_fit

def single_gaussian(x, a, m, s):
    """单个高斯函数"""
    return a * np.exp(-((x - m) / s) ** 2)

def multi_gaussian(x, *params):
    """支持任意数量高斯分量的拟合函数
    params参数格式:(a1, m1, s1, a2, m2, s2, ..., an, mn, sn)
    """
    n_clusters = len(params) // 3
    if len(params) % 3 != 0:
        raise ValueError("参数数量必须是3的倍数(每个高斯分量对应a、m、s三个参数)")
    
    y = np.zeros_like(x)
    for i in range(n_clusters):
        a = params[3 * i]
        m = params[3 * i + 1]
        s = params[3 * i + 2]
        y += single_gaussian(x, a, m, s)
    return y

2. 生成适配的bounds参数

根据指定的Cluster数量,按(a_min, m_min, s_min)重复n次生成下界,(a_max, m_max, s_max)重复n次生成上界:

# 定义参数范围
AmpMin = 0.01
AmpMax = 1000
CenMin = x.min()
CenMax = x.max()
WidMin = 0.1
WidMax = 100

# 指定高斯分量数量
n_clusters = 3  # 可根据需求修改为任意正整数

# 生成bounds
lower_bounds = [AmpMin, CenMin, WidMin] * n_clusters
upper_bounds = [AmpMax, CenMax, WidMax] * n_clusters

3. 调用curve_fit(需注意初始值p0)

多峰拟合的初始猜测值p0非常关键,合理的初始值能避免拟合陷入局部最优。以下是示例初始值生成逻辑(可根据实际数据调整):

# 生成初始猜测值p0
p0 = []
for i in range(n_clusters):
    # 中心位置在数据范围内均匀分布
    cen = CenMin + (CenMax - CenMin) * (i + 0.5) / n_clusters
    # 振幅初始为数据最大值的1/n
    amp = y.max() / n_clusters
    # 宽度初始为数据范围的1/(2n)
    wid = (CenMax - CenMin) / (2 * n_clusters)
    p0.extend([amp, cen, wid])

# 执行拟合
popt, pcov = curve_fit(multi_gaussian, x, y, p0=p0, bounds=(lower_bounds, upper_bounds))

# 解析拟合结果:拆分每个高斯分量的参数
fit_results = []
for i in range(n_clusters):
    a = popt[3 * i]
    m = popt[3 * i + 1]
    s = popt[3 * i + 2]
    fit_results.append({"振幅": a, "中心": m, "宽度": s})

可选参数顺序调整

如果偏好先传入所有振幅、再所有中心、再所有宽度的参数顺序,只需修改函数内部的参数拆分逻辑,并同步调整bounds和p0的生成顺序即可:

def multi_gaussian(x, *params):
    n_clusters = len(params) // 3
    a_list = params[:n_clusters]
    m_list = params[n_clusters:2*n_clusters]
    s_list = params[2*n_clusters:]
    
    y = np.zeros_like(x)
    for a, m, s in zip(a_list, m_list, s_list):
        y += single_gaussian(x, a, m, s)
    return y

# 对应调整bounds
lower_bounds = [AmpMin]*n_clusters + [CenMin]*n_clusters + [WidMin]*n_clusters
upper_bounds = [AmpMax]*n_clusters + [CenMax]*n_clusters + [WidMax]*n_clusters

# p0也同步调整
p0 = [y.max()/n_clusters]*n_clusters + \
     [CenMin + (CenMax-CenMin)*(i+0.5)/n_clusters for i in range(n_clusters)] + \
     [(CenMax-CenMin)/(2*n_clusters)]*n_clusters

内容的提问来源于stack exchange,提问作者user2458922

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:30:19