【问题标题】:Unable to fit an ECDF using scipy.optimize.curve_fit无法使用 scipy.optimize.curve_fit 拟合 ECDF
【发布时间】:2018-09-02 19:01:50
【问题描述】:

我正在尝试用平滑函数(小于 5 个参数)例如 广义逻辑函数来近似经验累积分布函数 (ECDF I want to approximate)。

然而,使用scipy.optimize.curve_fit,拟合操作给出了非常糟糕的近似值,或者它根本不起作用(取决于初始值)。变量series 表示我的数据存储为pandas.Series

from scipy.optimize import curve_fit

def fit_ecdf(x):
    x = np.sort(x)
    def result(v):
        return np.searchsorted(x, v, side='right') / x.size
    return result

ecdf = fit_ecdf(series)

def genlogistic(x, B, M, Q, v):
    return 1 / (1 + Q * np.exp(-B * (x - M))) ** (1 / v)

params = curve_fit(genlogistic, xdata = series, ydata = ecdf(series), p0 = (0.1, 10.0, 0.1, 0.1))[0]

我应该使用其他类型的函数来进行拟合吗? 有没有代码错误?

更新 - 1

按照要求,我链接到一个包含 the data 的 csv。

更新 - 2

经过大量搜索和反复试验,我发现了这个功能

f(x; a, b, c) = 1 - 1 / (1 + (x / b) ** a) ** c
with a = 4.61320000, b = 2.94570952, c = 0.5886922

它比另一个更适合。唯一的问题是 ECDF 在x=1 附近显示的一小步。如何修改f 以提高合身质量?我正在考虑添加某种仅在这些点中“相关”的功能。这是拟合的图形结果,其中蓝色实线表示 ECDF,虚线表示(x, f(x)) 点。

【问题讨论】:

  • 您能否提供一个简化的数据样本?(请参阅minimal reproducible example)以便测试适合它的解决方案
  • @xdze2 我更新了一个数据样本。 @mikuszefski 函数在x=0 的根不是绝对必要的。它可以返回一个小的值,并且我假装较大的x 函数转到1
  • @JamesPhillips 该功能似乎还可以,但显然不能很好地拟合数据。我正在尝试用另一个效果更好的函数来近似 ECDF。但是我想改善x=1附近的贴合度。
  • 我添加了图形结果和函数的参数。抱歉,一开始我忘记添加了。
  • 由于某些点的重复值比其他点多,您实际上将加权对这些数据点的拟合。我建议进行一个测试,对重复点的值进行平均并分析这些回归结果,看看数据的隐式加权是否有任何不同。

标签: python scipy curve-fitting


【解决方案1】:

我知道如何处理x=1 附近的那一小步。正如问题中所表达的那样,添加某种仅在该时间间隔内有意义的功能是改变游戏规则的方式。 “步骤”大约在 (1.7, 0.04) 处结束,所以我需要一种函数,可以为 x > 1.7 展平,并以 y = 0.04 作为渐近线。自然的选择(只是为了保持重点)是采用像f(x) = 1/exp(x) 这样的函数。 感谢 JamesPhillips,我还为回归选择了正确的数据(没有双值 = 没有超重点)。

Python 代码

from scipy.optimize import curve_fit

def fit_ecdf(x):
    x = np.sort(x)
    def result(v):
        return np.searchsorted(x, v, side = 'right') / x.size
    return result

ecdf = fit_ecdf(series)

unique_series = series.unique().tolist()

def cdf_interpolation(x, a, b, c, d):
    f_1 = 0.95 + (0 - 0.95) / (1 + (x / b) ** a) ** c + 0.05
    f_2 = (0 - 0.05)/(np.exp(d * x))
    return f_1 + f_2

params = curve_fit(cdf_interpolation, 
                   xdata = unique_series , 
                   ydata = ecdf(unique_series), 
                   p0 = (6.0, 3.0, 0.4, 1.0))[0]

参数

a = 6.03256462 
b = 2.89418871 
c = 0.42997956
d = 1.06864006

图形结果

【讨论】:

    【解决方案2】:

    我使用唯一值对 5 参数逻辑方程(参见图像和代码)进行了良好拟合,不确定低端曲线是否足以满足您的需求,请检查。

    import numpy as np
    
    def Sigmoidal_FiveParameterLogistic_model(x_in): # from zunzun.com
    
        # coefficients
        a = 9.9220221252324947E-01
        b = -3.1572339989462903E+00
        c = 2.2303376075685142E+00
        d = 2.6271495036080207E-02
        f = 3.4399008905318986E+00
    
        return d + (a - d) / np.power(1.0 + np.power(x_in / c, b), f)
    

    【讨论】:

    • 非常适合x>2.5。但是,使用带有 5 个参数的 sigmoidal 函数,您也可以推断出渐近线(ad)。这个设置有点奇怪,因为我们知道我们用于插值的点代表一个 ECDF。事实上,看图和参数,主要的不一致是sigmoid有y=d=0.026作为下渐近线。所以对于x=0,你会得到类似y = 0.026而不是0。您避免了“步骤”问题,但您构建了一个不像 CDF 那样处理较低 x 值的函数。
    • 我拟合下渐近线强制为零,而低端拟合不佳。我的建议是使用两个适合重叠数据范围的方程,例如适合低于 2.5 的低端和高于 2.0 的高端,当数据高于或低于重叠中心时,使用这些作为两者之间的切换地区。您可能还可以找到每个方程的参数少于五个的函数。如果您觉得这个想法合理,我可以再次使用我的 zunzun.com“函数查找器”进行方程式搜索。
    • 就我的目的而言,我认为两个函数之和的解决方案比将数据点一分为二并为每个段应用不同的函数要好。无论如何,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 2018-11-22
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 2020-06-07
    相关资源
    最近更新 更多