我怎样才能得到这个二次拟合到高原?

How can I get this quadratic fit to plateau?

我有两个变量,xy,它们是随机变量。我想在那个高原上给他们拟合一条曲线。我已经能够使用指数拟合来做到这一点,但我也想使用二次拟合来做到这一点。

我怎样才能使顶部变平? FWIW,生成的 y 数据使得没有值超过:4300。所以可能在新曲线中它应该有这个要求。

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

x = np.asarray([70,37,39,42,35,35,44,40,42,51,65,32,56,51,33,47,33,42,33,44,46,38,53,38,54,54,51,46,50,51,48,48,50,32,54,60,41,40,50,49,58,35,53,66,41,48,43,54,51])
y = np.asarray([3781,3036,3270,3366,2919,2966,3326,2812,3053,3496,3875,1823,3510,3615,2987,3589,2791,2819,1885,3570,3431,3095,3678,2297,3636,3569,3547,3553,3463,3422,3516,3538,3671,1888,3680,3775,2720,3450,3563,3345,3731,2145,3364,3928,2720,3621,3425,3687,3630])

def polyfit(x, y, degree):
    results = {}
    coeffs = np.polyfit(x, y, degree)

     # Polynomial Coefficients
    results['polynomial'] = coeffs.tolist()

    # r-squared, fit values, and average
    p = np.poly1d(coeffs)
    yhat = p(x)                       
    ybar = np.sum(y)/len(y)         
    ssreg = np.sum((yhat-ybar)**2)  
    sstot = np.sum((y - ybar)**2)   
    results['determination'] = ssreg / sstot

    return results, yhat, ybar

def plot_polyfit(x=None, y=None, degree=None):
    # degree = degree of the fitting polynomial
    xmin = min(x)
    xmax = max(x)
    fig, ax = plt.subplots(figsize=(5,4))
    p = np.poly1d(np.polyfit(x, y, degree))
    t = np.linspace(xmin, xmax, len(x))

    ax.plot(x, y, 'ok', t, p(t), '-', markersize=3, alpha=0.6, linewidth=2.5)

    results, yhat, ybar = polyfit(x,y,degree)
    R_squared = results['determination']
    textstr = r'$r^2=%.2f$' % (R_squared, )
    props = dict(boxstyle='square', facecolor='lightgray', alpha=0.5)

    fig.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=12,
            verticalalignment='top', bbox=props)

    results['polynomial'][0]

plot_polyfit(x=x, y=y, degree=2)

相比之下,当数据如此时,我可以使用相同的函数并使曲线更好地平稳:

x2 = np.asarray([0, 1, 2,  3,  4,  5,  6,  7,  8,  9,  10, 12])
y2 = np.asarray([2, 4, 8, 12, 14, 18, 20, 21, 22, 23,  24, 24])

plot_polyfit(x=x2, y=y2, degree=2)

@tsanisl 建议的编辑:

def plot_newfit(xdat, ydat):
    x,y = xdat, ydat
    xmax = 4300
    def new_fit(A,x,B):
        return A*(x - xmax)**2+B # testing this out

    fig, axs = plt.subplots(figsize=(5,4)) 

    # Find best fit.
    popt, pcov = curve_fit(new_fit, x, y)

    # Top plot
    # Plot data and best fit curve.
    axs.plot(x, y,'ok', alpha=0.6)
    axs.plot(np.sort(x), new_fit(np.sort(x), *popt),'-')

    #r2
    residuals = y - new_fit(x, *popt)
    ss_res = np.sum(residuals**2)
    ss_tot = np.sum((y-np.mean(y))**2)
    r_squared = 1 - (ss_res / ss_tot)
    r_squared

    # Add text
    textstr = r'$r^2=%.2f$' % (r_squared, )
    props = dict(boxstyle='square', facecolor='lightgray', alpha=0.5)
    fig.text(0.05, 0.95, textstr, transform=axs.transAxes, fontsize=12,
            verticalalignment='top', bbox=props)

plot_newfit(x,y)

我不太熟悉 scipy.optimise 但是,如果你找到包含 x-max 的点和包含你的 y-max 的点之间的欧几里德距离,将它分成两半并做一些trig,你可以使用那个坐标来强制你的二次通过它,或者在你的数组中使用它。 (同样不太熟悉 scipy.optimise 所以我不确定第一个选项是否可行,但第二个选项应该会减少向下曲线)

不明白我可以举证

您只需稍微修改 new_fit() 以适合 A、B 而不是 x 和 B。 将 xmax 设置为 peek 的所需位置。使用 x.max() 将保证拟合曲线在最后一个样本处变平。

    def new_fit(x, A, B):
        xmax = x.max() # or 4300
        return A*(x - xmax)**2+B # testing this out

结果: