如何解决scipy 奇怪的意外行为 curve_fit 正弦波的大数据集
出于某种原因,当我尝试将大量数据转换为正弦波时,它会失败并将其拟合到水平线上。有人能解释一下吗?
最少的工作代码:
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
# Seed the random number generator for reproducibility
import pandas
np.random.seed(0)
# Here it work as expected
# x_data = np.linspace(-5,5,num=50)
# y_data = 2.9 * np.sin(1.05 * x_data + 2) + 250 + np.random.normal(size=50)
# With this data it breaks
x_data = np.linspace(0,2500,num=2500)
y_data = -100 * np.sin(0.01 * x_data + 1) + 250 + np.random.normal(size=2500)
# And plot it
plt.figure(figsize=(6,4))
plt.scatter(x_data,y_data)
def test_func(x,a,b,c,d):
return a * np.sin(b * x + c) + d
# Used to fit the correct function
# params,params_covariance = optimize.curve_fit(test_func,x_data,y_data)
# making some guesses
params,y_data,p0=[-80,3,260])
print(params)
plt.figure(figsize=(6,label='Data')
plt.plot(x_data,test_func(x_data,*params),label='Fitted function')
plt.legend(loc='best')
plt.show()
有谁知道如何解决这个问题。我应该使用不同的拟合方法而不是最小二乘法吗?还是应该减少数据点的数量?
解决方法
根据您的数据,您可以使用更强大的 lmfit
而不是 scipy
。
特别是,您可以使用 SineModel
(有关详细信息,请参阅 here)。
SineModel
中的 lmfit
不适用于“移位”正弦波,但您可以轻松处理移位
y_data_offset = y_data.mean()
y_transformed = y_data - y_data_offset
plt.scatter(x_data,y_transformed)
plt.axhline(0,color='r')
现在你可以适应正弦波
from lmfit.models import SineModel
mod = SineModel()
pars = mod.guess(y_transformed,x=x_data)
out = mod.fit(y_transformed,pars,x=x_data)
您可以使用 print(out.fit_report())
检查结果并使用
plt.plot(x_data,y_data,lw=7,color='C1')
plt.plot(x_data,out.best_fit+y_data_offset,color='k')
# we add the offset ^^^^^^^^^^^^^
或使用内置绘图方法 out.plot_fit()
,请参阅 here 了解详情。
请注意,在 SineModel
中,所有参数“都被限制为非负”,因此您定义的负振幅 (-100) 在参数拟合结果中将为正 (+100)。所以相位也不会是 1 而是 π+1(PS:他们称 shift
相位)
print(out.best_values)
{'amplitude': 99.99631403054289,'frequency': 0.010001193681616227,'shift': 4.1400215410836605}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。