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

scipy curve_fit报参数协方差无法估计警告,拟合参数未更新

解决curve_fit无法拟合分段线性函数的问题

我看到你在尝试用curve_fit拟合带噪声的分段函数时,遇到了参数不更新、协方差估计失败的问题,这其实是因为你定义的函数不是连续可微的,直接导致优化算法无法有效工作。

问题根源分析

你当前的f函数里,过渡段用np.linspace(-1., 1., num=np.sum(linear))赋值的方式存在两个致命问题:

  • 突变的边界与非连续导数:当start或end变化时,哪些x属于过渡段是突然切换的(比如x=500可能瞬间从常数段跳到过渡段),函数在这些边界点的导数完全不存在。
  • 非平滑的参数响应:过渡段的取值是固定间隔的离散序列,不是随start/end平滑变化的连续函数——微调参数时,过渡段的所有点取值会直接跳变到新的linspace序列,残差平方和关于参数的梯度要么为0,要么无法计算,优化器根本找不到参数更新的方向,自然停在初始猜测值上。

解决方案:改用连续可微的分段线性函数

重新定义分段函数,让过渡段成为真正的连续线性插值:对于x在[start, end]区间内,y从-1线性变化到1,公式为:
y = -1 + 2 * (x - start) / (end - start)
这样整个函数在定义域内连续,且对start和end可微,curve_fit的梯度优化算法就能正常工作了。

修改后的完整代码

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

def f(x, start, end):
    res = np.empty_like(x)
    # 左常数段:x < start 时取值为-1
    res[x < start] = -1
    # 右常数段:x > end 时取值为1
    res[x > end] = 1
    # 线性过渡段:连续线性插值
    mask = (x >= start) & (x <= end)
    res[mask] = -1 + 2 * (x[mask] - start) / (end - start)
    return res

if __name__ == '__main__':
    xdata = np.linspace(0., 1000., 1000)
    ydata = -np.ones(1000)
    ydata[500:1000] = 1.
    ydata = ydata + np.random.normal(0., 0.25, len(ydata))
    
    # 初始猜测值
    popt, pcov = curve_fit(f, xdata, ydata, p0=[495., 505.])
    print(f"拟合参数:start={popt[0]:.2f}, end={popt[1]:.2f}")
    print(f"协方差矩阵:\n{pcov}")
    
    plt.figure()
    plt.plot(xdata, f(xdata, *popt), 'r-', label='拟合曲线')
    plt.scatter(xdata, ydata, s=5, c='b', label='带噪声数据')
    plt.legend()
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

效果说明

运行这段代码后,你会发现拟合出的start和end会接近真实值500,同时不会再出现协方差估计失败的警告。因为现在函数是光滑可微的,优化器能正确计算参数梯度,找到最小化残差平方和的参数值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:01:42