【问题标题】:scipy weird unexpected behavior curve_fit large data set for sin wavescipy 奇怪的意外行为 curve_fit 正弦波的大数据集
【发布时间】:2021-07-12 12:37:43
【问题描述】:

由于某种原因,当我尝试将大量数据转换为正弦波时,它会失败并适合水平线。谁能解释一下?

最少的工作代码:

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, params_covariance = optimize.curve_fit(test_func, x_data, y_data,
                                               p0=[-80, 3, 0, 260])

print(params)
plt.figure(figsize=(6, 4))
plt.scatter(x_data, y_data, label='Data')
plt.plot(x_data, test_func(x_data, *params),
         label='Fitted function')

plt.legend(loc='best')

plt.show()

有谁知道,如何解决这个问题。我应该使用不同的拟合方法而不是最小二乘吗?还是应该减少数据点的数量?

【问题讨论】:

  • 你试过lmfit吗? lmfit.github.io/lmfit-py/…
  • 你的适合确实工作,你只需要更好的起始值来为你的数据集不适合。您注释掉的示例甚至根本没有初始值。 curve_fit 是危险的错误并且(故意 - 是的,故意的!)误导您不提供初始值是合理的。它不是。初始值始终是必需的,它们应该是预期值的近似值,并为您正在建模的函数提供不平凡的结果。所以,简而言之:猜得更好。

标签: pandas numpy scipy curve-fitting scipy-optimize


【解决方案1】:

根据您的数据,您可以使用更强大的lmfit 而不是scipy

特别是,您可以使用SineModel(有关详细信息,请参阅here)。

lmfit 中的SineModel 不适用于“移位”正弦波,但您可以轻松处理移位操作

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}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 2017-12-28
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多