Python中正弦曲线拟合:如何为给定数据集拟合单峰正弦曲线
单峰正弦曲线拟合问题解决
数据集
xData = np.array([1.7, 8.8, 15, 25, 35, 45, 54.8, 60, 64.7, 70]) yData = np.array([30, 20, 13.2, 6.2, 3.9, 5.2, 10, 14.8, 20, 27.5])
问题描述
你已成功用scipy.optimize.curve_fit拟合抛物线,但正弦曲线拟合效果不佳,当前尝试代码及运行结果如下:
当前尝试代码
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit import scipy.interpolate as inp xData = np.array([1.7, 8.8, 15, 25, 35, 45, 54.8, 60, 64.7, 70]) yData = np.array([30, 20, 13.2, 6.2, 3.9, 5.2, 10, 14.8, 20, 27.5]) def model_parabola(x, a, b, c): return a * (x - b) ** 2 + c def model_sine(x, amp, omega, phase, c, z): return amp * np.sin(omega * (x - z) + phase) + c poptsin, pcovsine = curve_fit(model_sine, xData, yData, p0=[np.std(yData) *2 **0.5, 2 * np.pi, 0, np.mean(yData), 0]) popt, pcov = curve_fit(model_parabola, xData, yData, p0=[2, 3, 4]) # 抛物线拟合结果 aopt, bopt, copt = popt xmodel = np.linspace(min(xData), max(xData), 100) ymodel = model_parabola(xmodel, aopt, bopt, copt) print(poptsin) # 正弦曲线拟合结果 ampopt, omegaopt, phaseopt, ccopt, zopt = poptsin xSinModel = np.linspace(min(xData), max(xData), 100) ySinModel = model_sine(xSinModel, ampopt, omegaopt, phaseopt, ccopt, zopt) y_fit = model_sine(xSinModel, *poptsin) plt.scatter(xData, yData) plt.plot(xmodel, ymodel, 'r-') plt.plot(xSinModel, ySinModel, 'g-') plt.show()
当前运行结果

问题原因
正弦曲线拟合失败的核心问题有两个:
- 初始参数
p0设置严重不合理:你设置的omega为2*np.pi,会导致正弦曲线在x的小范围内振荡数十次,完全不符合数据的单峰趋势。 - 模型参数冗余:
omega*(x-z)+phase可合并为omega*x + (phase - omega*z),多余的参数z会增加拟合不确定性,导致算法难以收敛到合理结果。
修正方案
1. 简化正弦模型
去掉冗余参数,降低拟合难度:
def model_sine(x, amp, omega, phase, offset): return amp * np.sin(omega * x + phase) + offset
2. 设置合理初始参数
根据数据特征估算初始值:
amp(振幅):数据最大值30,最小值3.9,振幅约为(30-3.9)/2 ≈13omega(角频率):x范围1.7~70,数据呈现波峰到波峰的趋势,周期约为140,因此omega=2*np.pi/140≈0.045phase(相位):波谷在x≈35处,此时sin(omega*x + phase)=-1,计算得phase≈3*np.pi/2 - 0.045*35≈3.14offset(偏移量):数据平均值约为15
修正后完整代码
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit xData = np.array([1.7, 8.8, 15, 25, 35, 45, 54.8, 60, 64.7, 70]) yData = np.array([30, 20, 13.2, 6.2, 3.9, 5.2, 10, 14.8, 20, 27.5]) def model_parabola(x, a, b, c): return a * (x - b) ** 2 + c # 简化后的正弦模型 def model_sine(x, amp, omega, phase, offset): return amp * np.sin(omega * x + phase) + offset # 抛物线拟合(保留原逻辑) popt, pcov = curve_fit(model_parabola, xData, yData, p0=[2, 3, 4]) aopt, bopt, copt = popt xmodel = np.linspace(min(xData), max(xData), 100) ymodel = model_parabola(xmodel, aopt, bopt, copt) # 设置合理初始参数后拟合正弦曲线 p0_sin = [13, 0.045, 3.14, 15] poptsin, pcovsine = curve_fit(model_sine, xData, yData, p0=p0_sin) # 生成正弦拟合曲线 xSinModel = np.linspace(min(xData), max(xData), 100) ySinModel = model_sine(xSinModel, *poptsin) # 绘图并添加图例 plt.scatter(xData, yData, label='原始数据') plt.plot(xmodel, ymodel, 'r-', label='抛物线拟合') plt.plot(xSinModel, ySinModel, 'g-', label='正弦曲线拟合') plt.legend() plt.show() # 打印拟合参数 print("正弦曲线拟合参数:", poptsin)
修正后效果
修正后的正弦曲线会紧密贴合原始数据的单峰趋势,拟合效果与抛物线接近,且符合正弦曲线的数学特征。
内容的提问来源于stack exchange,提问作者Nob
相关产品推荐
相关产品推荐

