【问题标题】:How to fit Cos function to a list of integers without shrinking the X or Y axis in Python?如何在不缩小 Python 中的 X 或 Y 轴的情况下将 Cos 函数拟合到整数列表?
【发布时间】:2025-12-08 04:00:02
【问题描述】:

我有一个名为 img 的数字列表,其中包含 400 个数字。一旦我绘制它,我可以清楚地看到其中的 cos 模式。一旦我尝试使用 optimize.curve_fit 进行拟合,该函数将无法正确拟合,除非我将 img 除以一个大数并缩小 X 轴范围。例如在下面的代码中,rangeY 和 rangeX 是我用来分别在 Y 和 X 维度上缩小列表的因素。 在第一个示例中,您可以看到拟合效果很好:

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt

rangeY = 8000
rangeX = 3

def test_func(x, a, b, c, d):
    return a + b * np.cos(c * x + d)

def fitCurve (img):
    x_data = np.linspace(0,rangeX,num=400)
    y_data = []
    for i in range(0,len(img)):
        y_data += [img[i] / rangeY]
    y_data = np.array(y_data)

    param_bounds = ([-np.inf, 0, 0, -np.inf], [np.inf, np.inf, np.inf, np.inf])
    params, params_covariance = optimize.curve_fit(test_func, x_data, y_data,      bounds=param_bounds,maxfev=100000)
    y_curve = test_func(x_data, params[0], params[1], params[2], params[3])
    MSE = round(np.square(np.subtract(y_data, y_curve)).mean(), 5)
    return (params,y_curve,MSE,x_data,y_data)


img = [8452, 8421, 8498, 8521, 8427, 8523, 8667, 8196, 8515, 8110, 8551, 8732, 8189, 8429, 8539, 8360, 8622, 8726, 8529, 8412, 8465, 8497, 8724, 8201, 8804, 8990, 8732, 8985, 8671, 8675, 8450, 8959, 8865, 8665, 8776, 8822, 9230, 8749, 8758, 8849, 8753, 9108, 9100, 8964, 8808, 9352, 8786, 9070, 9359, 8895, 9131, 9117, 8994, 9087, 9352, 9163, 9073, 9190, 9277, 9073, 9276, 9413, 9395, 9223, 9353, 9420, 9462, 9512, 9512, 9571, 9580, 9595, 9593, 9639, 9622, 9647, 9710, 9710, 9725, 9758, 9785, 9814, 9831, 9862, 9889, 9902, 9921, 9941, 9964, 9992, 10050, 10091, 10131, 10131, 10133, 10179, 10177, 10164, 10241, 10291, 10332, 10332, 10316, 10332, 10332, 10333, 10340, 10333, 10333, 10368, 10385, 10391, 10391, 10403, 10439, 10454, 10428, 10407, 10428, 10459, 10480, 10523, 10530, 10539, 10556, 10562, 10586, 10606, 10592, 10612, 10621, 10621, 10587, 10587, 10574, 10574, 10574, 10574, 10587, 10594, 10584, 10597, 10598, 10599, 10606, 10677, 10620, 10620, 10677, 10677, 10633, 10633, 10620, 10633, 10619, 10619, 10619, 10619, 10599, 10599, 10599, 10621, 10616, 10621, 10621, 10616, 10593, 10635, 10582, 10521, 10514, 10484, 10474, 10468, 10456, 10475, 10481, 10481, 10426, 10413, 10386, 10380, 10370, 10370, 10365, 10363, 10336, 10336, 10322, 10318, 10275, 10299, 10275, 10299, 10299, 10275, 10275, 10272, 10264, 10250, 10201, 10184, 10182, 10178, 10176, 10176, 10136, 10178, 10163, 10163, 10170, 10170, 10111, 10147, 10081, 10081, 10074, 10055, 10055, 10063, 10063, 10055, 10030, 10013, 10013, 9958, 9905, 9872, 9864, 9855, 9855, 9864, 9896, 9899, 9899, 9900, 9901, 9923, 9901, 9843, 9836, 9830, 9830, 9810, 9802, 9801, 9783, 9760, 9761, 9739, 9760, 9739, 9712, 9771, 9771, 9734, 9722, 9675, 9632, 9632, 9610, 9624, 9610, 9579, 9597, 9570, 9579, 9555, 9519, 9519, 9517, 9517, 9516, 9516, 9495, 9480, 9428, 9426, 9408, 9408, 9379, 9379, 9391, 9379, 9358, 9327, 9319, 9304, 9297, 9280, 9280, 9288, 9271, 9288, 9297, 9295, 9246, 9246, 9240, 9267, 9246, 9222, 9187, 9169, 9154, 9139, 9100, 9074, 9101, 9101, 9100, 9076, 9074, 9101, 9104, 9116, 9140, 9143, 9133, 9106, 9081, 9090, 9081, 9077, 9067, 9079, 9093, 9093, 9082, 9082, 9079, 9076, 9025, 9017, 9006, 9006, 8991, 9015, 9015, 9006, 9039, 9063, 9096, 9106, 9120, 9120, 9120, 9096, 9113, 9078, 9071, 9078, 9102, 9102, 9117, 9117, 9117, 9117, 9125, 9126, 9145, 9164, 9170, 9178, 9190, 9237, 9265, 9265, 9245, 9251, 9245, 9245, 9251, 9239, 9260, 9267, 9267, 9267, 9259, 9277, 9277, 9261, 9261, 9261, 9286, 9272, 9266, 9266, 9313, 9329, 9313, 9313, 9331, 9328, 9335, 9335, 9385, 9406, 9406, 9403]

params, y_curve, MSE, x_data, y_data = fitCurve(img)
plt.figure(figsize=(6, 4))
plt.scatter(x_data, y_data, label='Data')
plt.plot(x_data, y_curve, color="red", label='Fitted function')
plt.legend(loc='best')
plt.show()

现在,如果我将 rangeY 更改为较小的数字,例如 100,拟合将无法正常工作,因此对于相同的代码:

rangeY = 100
rangeX = 3

或者,如果我不缩小 X 轴 (rangeX=400),它仍然不适合:

rangeY = 8000
rangeX = 400

现在我的问题是:有没有办法在不缩小 Y 轴和 X 轴范围的情况下,或者至少不缩小 X 轴的情况下,正确地将红色曲线拟合到蓝点上? 如果没有,我应该如何找到 rangeX 和 rangeY 的正确值? 谢谢

【问题讨论】:

    标签: python scipy curve-fitting scipy-optimize


    【解决方案1】:

    在研究了 optimize.curve_fit 的手册后,我发现这需要 func 中“c”的边界限制。因为这个参数取决于曲线的T所以它肯定需要一个限制。所以在这里我们有了新的限制和漂亮的拟合曲线,对我自己表示敬意:-)

    rangeX = 400
    rangeY = 8000
    param_bounds = ([-np.inf, 0, 0, -np.inf], [np.inf, np.inf, 0.02, np.inf])
    

    【讨论】: