我想用一个平滑函数(小于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))
点。
我找到了如何处理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
图形结果
我使用唯一值得到了一个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)