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

如何用Scipy curve_fit拟合曲线?遇参数协方差估计错误

问题分析与解决方案

核心问题

  1. 模型趋势与数据完全不符:你定义的func(x, a, b, c) = a*np.exp(-b*x) + c是递减曲线(当b>0时,x越大,值越小),但你的数据是递增趋势(从0.5逐步增长到1),这是拟合失败的根本原因。
  2. x值过大导致数值溢出问题:x的取值范围是6529-6629,直接代入exp(-b*x)会因为x过大,结果趋近于0,优化器无法找到有效的参数组合,最终只能拟合出水平线(a≈0,结果为c)。
  3. 未提供初始参数猜测:curve_fit默认初始参数为[1,1,1],对于你的数据来说完全不合理,导致优化器收敛到局部最优。

解决方案

1. 修正模型为递增的饱和指数曲线

改用符合数据趋势的模型,即指数增长趋近于饱和值的形式,这样x越大,y越接近饱和值,和你的数据特征匹配:

def func_scaled(x_scaled, a, b, c):
    # x_scaled是中心化后的x,c是饱和值,a是初始差值,b是增长速率
    return c - a * np.exp(-b * x_scaled)

2. 对x进行中心化处理

将x减去最小值,缩小数值范围,让指数项有合理的变化空间,避免数值溢出:

x_min = xdata.min()
x_scaled = xdata - x_min

3. 提供合理的初始参数猜测

根据数据特征给出初始值,帮助优化器快速收敛:

  • c:数据最大值接近1,初始值设为1
  • a:初始值设为c - ydata.min(),即1 - 0.547 ≈ 0.45
  • b:设为小正数0.1(控制增长快慢)

完整代码

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

# 定义修正后的拟合模型
def func_scaled(x_scaled, a, b, c):
    return c - a * np.exp(-b * x_scaled)

# 原始数据
x = [6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629]
y = [0.547409184506862,0.548439334507089,0.548707663683029,0.549517457040911,0.549928046272648,0.552133076225856,0.553680404362389,0.554546610865359,0.556183559635298,0.55702393264449,0.558127603440548,0.56005701419833,0.567268696243044,0.567959158455945,0.56888383955428,0.570002946460703,0.571738099634388,0.571781066314887,0.572492904162659,0.573363360104158,0.575401312020501,0.579556244995718,0.581790310757611,0.583406644934125,0.583431253838386,0.584646128487338,0.591634693424932,0.593621181449664,0.596918227952608,0.597537299010122,0.597822020010253,0.598891783912097,0.599584877929425,0.600869677067233,0.605499427101361,0.60658392374002,0.607408603951367,0.608003672935112,0.612816417541406,0.614176393253985,0.615691612727725,0.617134841882831,0.624502603183639,0.627504005062751,0.62811483139368,0.630923224681103,0.631913519350306,0.632861774084856,0.633396927216081,0.634723100574364,0.636823036518848,0.637335872514631,0.641989703420432,0.645848889736627,0.65711344945379,0.657128729116295,0.663572015593525,0.663936607768306,0.664261916284895,0.665497047151865,0.675768594810369,0.676207425367557,0.67770213122942,0.684362066388147,0.686091459831405,0.68923449405901,0.696555953074396,0.699523852803358,0.700114629853266,0.700439968032363,0.70422912133774,0.709054418203755,0.718323675919034,0.720874110082631,0.731420313805414,0.740339970645214,0.743941832408661,0.744098264483215,0.755637715557576,0.770607412727517,0.772170144147719,0.77386595160397,0.782346429315201,0.793536926034814,0.799814727138212,0.811806170429752,0.820389958104833,0.823442687233217,0.836431157138314,0.837230603981482,0.84457830759536,0.849472002016762,0.853064650303987,0.864143132487712,0.875848713252245,0.879457500784825,0.906226501241044,0.938124902423877,0.957251151492073,0.984140865987764,1]

xdata = np.array(x)
ydata = np.array(y)

# 中心化x,缩小数值范围
x_min = xdata.min()
x_scaled = xdata - x_min

# 初始参数猜测
p0 = [0.45, 0.1, 1.0]

# 执行拟合
popt, pcov = curve_fit(func_scaled, x_scaled, ydata, p0=p0)
a_fit, b_fit, c_fit = popt

# 生成拟合曲线
y_fit = func_scaled(x_scaled, *popt)

# 可视化结果
plt.figure(figsize=(10,6))
plt.plot(xdata, ydata, 'b.', label='原始数据')
plt.plot(xdata, y_fit, 'r-', label=f'拟合曲线: a={a_fit:.3f}, b={b_fit:.3f}, c={c_fit:.3f}')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()

# 如需对原始x求导,转换为原始x的模型并定义导数函数
def func_original(x, a, b, c, x_min):
    return c - a * np.exp(-b * (x - x_min))

def dfunc_original(x, a, b, c, x_min):
    return a * b * np.exp(-b * (x - x_min))

# 示例:计算x=6550处的导数
x_example = 6550
derivative = dfunc_original(x_example, a_fit, b_fit, c_fit, x_min)
print(f"x={x_example}处的导数: {derivative:.6f}")

效果说明

  • 修正后的模型完全匹配数据递增并趋近于饱和的趋势,拟合结果会和你期望的示例图一致。
  • 中心化处理解决了x值过大导致的数值问题,curve_fit可以正常估计参数和协方差,不会再出现警告。
  • 初始参数引导优化器直接向合理方向收敛,避免陷入局部最优解。

内容的提问来源于stack exchange,提问作者la.poubelle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:01:05