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

scipy.optimize.curve_fit添加bounds时触发x0维度报错排查

问题原因

给scipy.optimize.curve_fit传bounds参数时触发ValueError: x0 must have at most 1 dimension,本质是参数写法不符合curve_fit的接口要求:

  • 传入的初始猜测p0_array是形状为(8,3)的二维数组:不传bounds时curve_fit默认使用的无约束优化器不会严格校验初始值维度,靠原写法里params + *args的参数处理逻辑刚好能凑出多峰参数结构;一旦传入bounds,就会切换到带边界约束的优化器,强制要求初始值x0必须是一维结构,直接触发维度报错
  • 自定义的multi_lorentzian函数参数签名不规范:curve_fit会将拟合参数按顺序逐个传入模型函数,原写法的参数处理逻辑在边界校验流程中无法正确解析参数
  • 传入的bounds_array仅包含3组上下限,对应不上8个洛伦兹峰合计24个待拟合参数(每个峰含振幅、中心、半宽3个参数),维度完全不匹配
修复方法
  1. 重写multi_lorentzian函数,直接接收展平的一维参数,在函数内部完成参数reshape,去掉冗余的*args分支处理逻辑
  2. 将初始猜测p0_array展平为长度24的一维数组再传入curve_fit
  3. 按24个待拟合参数的顺序,生成对应长度的边界数组:每个峰的参数边界一致,直接将单组边界重复8次即可
  4. 拟合完成后,再将返回的一维popt结果reshape为(8,3)的结构,方便后续拆分单峰、计算误差
修复后可运行代码
import numpy as np
import scipy as scipy

# 洛伦兹单峰模型
def lorentzian(x, amp, cen, wid):
    return amp*wid**2/((x-cen)**2+wid**2)

# 多洛伦兹峰模型,直接接收展平的一维参数
def multi_lorentzian(x, *params):
    # 将一维参数重构为 (峰数, 3) 的结构,3对应amp/cen/wid
    params = np.array(params).reshape(-1, 3)
    total_curve = 0
    for amp, cen, wid in params:
        total_curve += lorentzian(x, amp, cen, wid)
    return total_curve

##############################################################################
# 生成测试数据
samples = 200
start = 2.75
stop = 3
x_array = np.linspace(start, stop, samples) # 频率,单位GHz
amp_array = np.random.uniform(0.03, 0.1, 8) # 对比度范围3%~10%
cen_array = [2.81, 2.829, 2.831, 2.848, 2.897, 2.914, 2.9165, 2.932]
wid_array = [0.003]*8

y_array = 1 - multi_lorentzian(x_array, *np.array([amp_array, cen_array, wid_array]).T.flatten())  
y_noise = y_array + np.random.normal(0, 1, samples)*1e-3
# 反转y轴,将谷值转为峰值方便拟合
y_noise_inv = -y_noise + 1
##############################################################################
# 生成拟合初始值
heights= np.random.uniform(0.03, 0.1, 8)
widths = np.random.uniform(0.002, 0.004, 8)
center_guess = cen_array + np.random.normal(0, 1, 8)*1e-3
p0_array = np.array([heights, center_guess, widths]).T.flatten() 
# 生成对应24个参数的边界:每个峰的amp∈[0,1], cen∈[2.75,3], wid∈[0,0.5]
bounds_array = (
    [0., 2.75, 0.]*8, 
    [1., 3., 0.5]*8
)

popt_y, pcov_y = scipy.optimize.curve_fit(
    multi_lorentzian, 
    x_array, 
    y_noise_inv,
    p0=p0_array, 
    bounds=bounds_array
)

# 重构拟合结果为(8,3)结构
popt_y = popt_y.reshape(len(popt_y)//3, 3)
single_peaks = [lorentzian(x_array, i, j, k) for i,j,k in popt_y]
perr_y = np.sqrt(np.diag(pcov_y))
residual_y = y_noise_inv - multi_lorentzian(x_array, *popt_y.flatten())
ss_res = np.sum(residual_y**2)
ss_tot = np.sum((y_noise_inv-np.mean(y_noise_inv))**2)
r_squared = 1 - (ss_res / ss_tot)

注:如果初始值随机偏移过大可能出现收敛不佳的问题,可根据实际峰值检测结果调整初始猜测即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:27:06