如何强制scipy.optimize.curve_fit修复第一点?

时间:2018-03-07 11:43:03

标签: python scipy curve-fitting least-squares

我使用此代码通过使用scipy.optimize.curve_fit

拟合指数来平滑数据
def smooth_data_v1(x_arr,y_arr):
    def func(x, a, b, c):
        return a*np.exp(-b*x)+c

    #Scale data
    y = y_orig / 10000.0
    x = 500.0 * x_orig

    popt, pcov = curve_fit(func, x, y, p0=(1, 0.01, 1))

    y_smooth = func(x, *popt) # Calcaulate smoothed values for same points

    #Undo scaling
    y_final = y_smooth * 10000.0

    return y_final

我想要估计的指数曲线要经过第一点。

不好的情况:

enter image description here

好案例:

enter image description here

我尝试使用第一个点x0,y0:

删除最后一个参数
def smooth_data_v2(x_orig,y_orig):
    x0 = x_orig[0]
    y0 = y_orig[0]

    def func(x, a, b):
        return a*np.exp(-b*x)+y0-a*np.exp(-b*x0)

    #Scale data
    y = y_orig / 10000.0
    x = 500.0 * x_orig

    popt, pcov = curve_fit(func, x, y, p0=(1, 0.01))

    y_smooth = func(x, *popt) # Calcaulate smoothed values for same points

    #Undo scaling
    y_final = y_smooth * 10000.0

    return y_final

如果出了问题我得到了:

enter image description here

a param真的很大 popt [ 4.45028144e+05 2.74698863e+01]

有什么想法吗?

更新

数据示例

x_orig [  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.]
y_orig [ 445057.  447635.  450213.  425089.  391746.  350725.  285433.  269027.
  243835.  230587.  216757.  202927.  189097.  175267.  161437.]

2 个答案:

答案 0 :(得分:2)

Scipy curve_fit允许传递参数sigma,该参数被设计为加权拟合的标准偏差。但是这个数组可以填充任意数据:

from scipy.optimize import curve_fit

def smooth_data_v1(x_arr,y_arr):
    def func(x, a, b, c):
        return a*np.exp(-b*x)+c

    #create the weighting array
    y_weight = np.empty(len(y_arr))
    #high pseudo-sd values, meaning less weighting in the fit
    y_weight.fill(10)
    #low values for point 0 and the last points, meaning more weighting during the fit procedure 
    y_weight[0] = y_weight[-5:-1] = 0.1

    popt, pcov = curve_fit(func, x_arr, y_arr, p0=(y_arr[0], 1, 1), sigma = y_weight, absolute_sigma = True)
    print("a, b, c:", *popt)
    y_smooth = func(x_arr, *popt)

    return y_smooth


x_orig = np.asarray([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14])
y_orig = np.asarray([ 445057,  447635,  450213,  425089,  391746,  350725,  285433,  269027,
  243835,  230587,  216757,  202927,  189097,  175267,  161437])

print(smooth_data_v1(x_orig, y_orig))

正如您所看到的,现在第一个和最后一个点接近原始值,但这个"值的钳位"有时会为其余的数据点付出代价 您可能还注意到,我删除了您的重新缩放部分。 Imho,在曲线拟合程序之前不应该这样做。通常最好使用原始数据。此外,您的数据并非由指数函数很好地表示,因此微小的b值。

答案 1 :(得分:0)

如何更改您尝试适合的功能的定义?

def func(x, a, b, c):
    return (y_arr[0] - c)*np.exp(-b*(x - x_arr[0]))+c

根据定义,此函数始终完美地符合第一点,但除此之外可以执行当前函数所做的任何操作。