使用Scipy curve_fit拟合指数函数结果偏差过大求排查
问题分析与修复方案
你的代码出现拟合结果量级偏差极大的问题,核心原因是模型函数的参数顺序不符合curve_fit的要求,另外还有两个次要问题影响拟合效果,我一步步给你拆解:
1. 核心问题:模型函数参数顺序错误
scipy.optimize.curve_fit要求模型函数的第一个参数必须是自变量(也就是你的时间序列range_thing),后续参数才是需要拟合的参数(A和c)。但你定义的函数把拟合参数A、c放在了自变量t的前面:
def simple_DE(A,c,t): return A*math.e**(c*t)
这会导致curve_fit错误地将输入的x值(range_thing)传递给参数A,而不是自变量t,直接导致拟合完全偏离预期。
2. 次要问题1:数组运算兼容性差
你使用了math.e**(c*t),虽然对于简单的标量运算没问题,但range_thing是numpy数组,更推荐使用numpy提供的np.exp()函数,它能更高效、安全地处理数组运算,避免潜在的类型错误。
3. 次要问题2:缺乏合理的初始参数猜测
指数函数的拟合对初始参数很敏感,curve_fit默认的初始值(全1)可能无法收敛到全局最优解。给一个接近真实值的初始猜测,能大幅提升拟合的准确性。
修正后的完整代码
import matplotlib.pyplot as plt from scipy.optimize import curve_fit import numpy as np cases_DE = [16,18,26,48,74,79,130,165,203,262,545,670,800,1040,1224,1565,1966,2745,3675,4599,5813, 7272, 9367, 12327] # 修正参数顺序:自变量t放在第一位,拟合参数A、c在后 def simple_DE(t, A, c): return A * np.exp(c * t) range_thing = np.array(range(len(cases_DE))) # 提供合理的初始参数猜测:A取初始病例数,c根据数据增长粗略估算 p0 = [16, 0.3] # 调整bounds:A不能为负数(病例数不可能是负的),c限制在0到1的合理增长范围内 popt, pcov = curve_fit(simple_DE, range_thing, cases_DE, p0=p0, bounds=((0, 0), (np.inf, 1))) print("拟合参数A和c:", popt) # 注意调用函数的顺序:自变量t放在最后 plt.scatter(range_thing, simple_DE(range_thing, *popt), label='拟合曲线', color='r') plt.scatter(range_thing, cases_DE, label='原始数据') print("第21天(索引20)的拟合值:", simple_DE(20, *popt)) plt.xlabel('天数索引') plt.ylabel('病例数') plt.legend() plt.show()
验证效果
修正后,你会得到接近真实数据的拟合结果,比如拟合出的A应该在15左右(接近初始病例数16),c大概在0.25-0.3之间,对应合理的日增长速率。第20天的拟合值会和真实的5813非常接近。
内容的提问来源于stack exchange,提问作者user45757
相关产品推荐
相关产品推荐

