如何优化scipy curve_fit的正弦函数曲线拟合效果?
如何优化正弦函数对测点数据的拟合效果
尝试用正弦函数拟合一组测点数据,拟合效果不理想,调整curve_fit参数也无法改善,可通过以下方案优化:
原始代码与拟合问题
from scipy.optimize import curve_fit as cf import numpy as np from matplotlib import pyplot as plt xdata = np.array([0. , 0.02, 0.04, 0.06, 0.08, 0.1 , 0.12, 0.14, 0.16, 0.18, 0.2 , 0.22, 0.24, 0.26, 0.28, 0.3 , 0.32, 0.34, 0.36, 0.38, 0.4 , 0.42, 0.44, 0.46, 0.48, 0.5 , 0.52, 0.54, 0.56, 0.58, 0.6 , 0.62, 0.64, 0.66, 0.68, 0.7 , 0.72, 0.74, 0.76, 0.78, 0.8 , 0.82, 0.84, 0.86, 0.88, 0.9 , 0.92, 0.94, 0.96, 0.98, 1. , 1.02, 1.04, 1.06, 1.08, 1.1 , 1.12]) ydata = np.array([37.5, 36.4, 37.1, 37.3, 38.2, 38.4, 38.1, 36.7, 34.3, 32.2, 33.1, 31.8, 33.4, 35.7, 37.8, 38.3, 38.1, 37. , 34.9, 32.5, 31.6, 31.7, 33.5, 35.5, 37.8, 38.4, 38.3, 36.9, 34.8, 32.2, 33.9, 31.6, 33.3, 35.5, 37.6, 38.3, 38.2, 36.7, 34.8, 32.4, 31.5, 32.1, 33.3, 35.5, 37.2, 38.3, 38.3, 36.8, 34.5, 32.3, 31.6, 31.8, 33.3, 35.7, 37.8, 38.4, 38.2]) def sin_fun(x,a,b,c,d): return a*np.sin(b*x+c)+d p_opt,p_cov=cf(sin_fun,xdata,ydata ) print(p_opt) plt.plot(xdata,sin_fun(xdata,*p_opt)) plt.plot(xdata,ydata, 'r') plt.show()

问题根源
curve_fit默认使用全1的初始参数猜测,对于正弦函数拟合极易陷入局部最优解——尤其是当数据的周期、振幅、基线均值与1偏差较大时。你的数据呈现明显周期性波动,核心问题是未提供合理的初始拟合参数。
优化方案
1. 基于数据特征计算初始参数
通过数据的统计特征估算初始参数,让拟合从接近最优解的位置开始迭代:
- 偏移量
d:取数据的均值(正弦函数的基线) - 振幅
a:取数据最大值与最小值差值的一半 - 角频率
b:观察数据周期,你的数据在x∈[0,0.4]完成一个周期,因此周期T≈0.4,角频率b=2π/T≈15.7 - 相位
c:先设为0,后续由拟合迭代优化
2. 带初始参数的拟合代码
from scipy.optimize import curve_fit as cf import numpy as np from matplotlib import pyplot as plt xdata = np.array([0. , 0.02, 0.04, 0.06, 0.08, 0.1 , 0.12, 0.14, 0.16, 0.18, 0.2 , 0.22, 0.24, 0.26, 0.28, 0.3 , 0.32, 0.34, 0.36, 0.38, 0.4 , 0.42, 0.44, 0.46, 0.48, 0.5 , 0.52, 0.54, 0.56, 0.58, 0.6 , 0.62, 0.64, 0.66, 0.68, 0.7 , 0.72, 0.74, 0.76, 0.78, 0.8 , 0.82, 0.84, 0.86, 0.88, 0.9 , 0.92, 0.94, 0.96, 0.98, 1. , 1.02, 1.04, 1.06, 1.08, 1.1 , 1.12]) ydata = np.array([37.5, 36.4, 37.1, 37.3, 38.2, 38.4, 38.1, 36.7, 34.3, 32.2, 33.1, 31.8, 33.4, 35.7, 37.8, 38.3, 38.1, 37. , 34.9, 32.5, 31.6, 31.7, 33.5, 35.5, 37.8, 38.4, 38.3, 36.9, 34.8, 32.2, 33.9, 31.6, 33.3, 35.5, 37.6, 38.3, 38.2, 36.7, 34.8, 32.4, 31.5, 32.1, 33.3, 35.5, 37.2, 38.3, 38.3, 36.8, 34.5, 32.3, 31.6, 31.8, 33.3, 35.7, 37.8, 38.4, 38.2]) def sin_fun(x,a,b,c,d): return a*np.sin(b*x+c)+d # 计算初始参数 d_init = np.mean(ydata) a_init = (np.max(ydata) - np.min(ydata)) / 2 b_init = 2 * np.pi / 0.4 # 周期T≈0.4 c_init = 0 p0 = [a_init, b_init, c_init, d_init] p_opt, p_cov = cf(sin_fun, xdata, ydata, p0=p0) print("优化后的参数:", p_opt) plt.plot(xdata, sin_fun(xdata, *p_opt), label='拟合曲线') plt.plot(xdata, ydata, 'r.', label='原始数据') plt.legend() plt.show()
3. 额外优化方向
- 若单正弦函数仍无法完美拟合,可尝试叠加多阶谐波,比如使用
a1*sin(b*x+c1) + a2*sin(2*b*x+c2) + d的形式,注意同步提供对应初始参数 - 若数据含噪声,可给
curve_fit传入sigma参数指定数据点权重,或使用method='trf'(Trust Region Reflective)方法,提升拟合稳健性
内容的提问来源于stack exchange,提问作者rpapa
相关产品推荐
相关产品推荐

