首页 文章

曲线拟合过去的最后一个数据点

提问于
浏览
1

我试图将曲线拟合到一组数据点,但希望保留某些特征 .

就像在这张图中一样,我的曲线几乎最终是线性的,而其中一些则不是 . 我需要一个函数形式来在给定的数据点之间插入或者超过最后给定的点 .

曲线是使用简单回归创建的

def func(x, d, b, c):
    return c + b * np.sqrt(x) + d * x

enter image description here

我现在的问题是,确保在最后一个数据点之后出现正斜率的最佳方法是什么?在我的应用中,即使数据如此,在增加音量的同时降低成本也没有意义 .

我想保持订单尽可能低,也许3还是没问题 .

用于创建具有负斜率的曲线的数据是

x_data = [     100,      560,      791,     1117,     1576,     2225,
       3141,     4434,     6258,     8834,    12470,    17603,
      24848,    35075,    49511,    69889,    98654,   139258,
     196573,   277479,   391684,   552893,   780453,  1101672,
    1555099,  2195148,  3098628,  4373963,  6174201,  8715381,
   12302462, 17365915]
y_data = [  7,   8,   9,  10,  11,  12,  14,  16,  21,  27,  32,  30,  31,
    38,  49,  65,  86, 108, 130, 156, 183, 211, 240, 272, 307, 346,
   389, 436, 490, 549, 473, 536]

而对于积极的一个

x_data = [     100,      653,      950,     1383,     2013,     2930,
       4265,     6207,     9034,    13148,    19136,    27851,
      40535,    58996,    85865,   124969,   181884,   264718,
     385277,   560741,   816117,  1187796,  1728748,  2516062,
    3661939,  5329675,  7756940, 11289641, 16431220, 23914400,
   34805603, 50656927]
y_data = [  6,   6,   7,   7,   8,   8,   9,  10,  11,  12,  14,  16,  18,
    21,  25,  29,  35,  42,  50,  60,  72,  87, 105, 128, 156, 190,
   232, 284, 347, 426, 522, 640]

曲线拟合通过使用简单完成

popt, pcov = curve_fit(func, x_data, y_data)

对于情节

plt.plot(xdata, func(xdata, *popt), 'g--', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt))
plt.plot(x_data, y_data, 'ro')
plt.xlabel('Volume')
plt.ylabel('Costs')
plt.show()

1 回答

  • 1

    一个简单的解决方案可能如下所示:

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.optimize import least_squares
    
    def fit_function(x, a, b, c, d):
        return a**2 + b**2 * x + c**2 * abs(x)**d 
    
    def residuals( params, xData, yData):
        diff = [ fit_function(x, *params ) - y for x, y in zip( xData, yData ) ]
        return diff
    
    fit1 = least_squares( residuals, [ .1, .1, .1, .5 ], loss='soft_l1', args=( x1Data, y1Data ) )
    print fit1.x
    fit2 = least_squares( residuals, [ .1, .1, .1, .5 ], loss='soft_l1', args=( x2Data, y2Data ) )
    print fit2.x
    
    testX1 = np.linspace(0, 1.1 * max( x1Data ), 100 )
    testX2 = np.linspace(0, 1.1 * max( x2Data ), 100 )
    testY1 = [ fit_function( x, *( fit1.x ) ) for x in testX1 ]
    testY2 = [ fit_function( x, *( fit2.x ) ) for x in testX2 ]
    
    fig = plt.figure()
    ax = fig.add_subplot( 1, 1, 1 )
    ax.scatter( x1Data, y1Data )
    ax.scatter( x2Data, y2Data )
    ax.plot( testX1, testY1 )
    ax.plot( testX2, testY2 )
    plt.show()
    

    提供

    >>[ 1.00232004e-01 -1.10838455e-04  2.50434266e-01  5.73214256e-01]
    >>[ 1.00104293e-01 -2.57749592e-05  1.83726191e-01  5.55926678e-01]
    

    soft fit

    它只是将参数作为正方形,因此确保正斜率 . 当然,如果遵循数据集1末尾的减少点,则拟合变得更糟 . 关于这一点,我会说这些只是统计异常值 . 因此,我使用 least_squares ,它可以解决这个问题 . 有关详细信息,请参阅this doc . 根据实际数据集的方式,我预计零容量会产生零成本,因此拟合函数中的常数项似乎没有意义 .

    因此,如果函数只是 a**2 * x + b**2 * sqrt(x) 类型,它看起来像:

    simplified

    其中绿色图形是 leastsq 的结果,即没有 least_squaresf_scale 选项 .

相关问题