如何使用Scipy Optimization提升慕尼黑气温数据曲线拟合精度
提升温度数据拟合精度的方法
1. 给拟合算法提供合理的初始参数猜测
scipy.optimize.curve_fit默认用[1,1,1]作为初始参数,这容易导致算法陷入局部最优解。你可以先根据数据特征估算更贴合的初始参数:
- 均值
c:取温度的平均值 - 振幅
a:取温度极差的一半((最大值-最小值)/2) - 相位
b:根据温度峰值的时间调整(比如慕尼黑7月温度最高,对应余弦函数的峰值,计算对应的相位)
修改后的代码:
import numpy as np import matplotlib.pyplot as plt from scipy import optimize def func(t, a, b, c): return a * np.cos(2 * np.pi * t + b) + c date, temperature = np.loadtxt('munich_temperatures_average.txt', unpack=True) # 估算初始参数 c_init = np.mean(temperature) a_init = (np.max(temperature) - np.min(temperature)) / 2 # 7月对应年份小数0.5,此时cos(2π*0.5 + b)=1 → 2π*0.5 + b = 2πk → 取b=-π b_init = -np.pi # 传入初始参数p0 result, _ = optimize.curve_fit(func, date, temperature, p0=[a_init, b_init, c_init]) plt.plot(date, temperature, '.') plt.plot(date, func(date, *result), c='red', zorder=10) plt.ylim([-20, 30]) plt.xlabel("Year", fontsize=18) plt.ylabel("Temperature", fontsize=18) plt.show()
2. 给模型加入长期趋势项
实际温度数据存在缓慢的长期上升趋势,单一余弦函数无法捕捉这个变化。可以给模型添加线性趋势项:
import numpy as np import matplotlib.pyplot as plt from scipy import optimize def func(t, a, b, c, d): # d*t 是线性趋势项,捕捉温度长期变化 return a * np.cos(2 * np.pi * t + b) + c + d * t date, temperature = np.loadtxt('munich_temperatures_average.txt', unpack=True) # 估算初始参数 c_init = np.mean(temperature) a_init = (np.max(temperature) - np.min(temperature)) / 2 b_init = -np.pi d_init = 0.05 # 初始猜测每年温度上升0.05度 result, _ = optimize.curve_fit(func, date, temperature, p0=[a_init, b_init, c_init, d_init]) plt.plot(date, temperature, '.') plt.plot(date, func(date, *result), c='red', zorder=10) plt.ylim([-20, 30]) plt.xlabel("Year", fontsize=18) plt.ylabel("Temperature", fontsize=18) plt.show()
3. 进一步优化方向
- 可以尝试加入二次趋势项(如
e*t**2),捕捉更复杂的长期变化 - 打印拟合得到的参数,对比实际数据特征,微调初始猜测值
内容的提问来源于stack exchange,提问作者Bilal
相关产品推荐
相关产品推荐

