假设我有一个样本,我有理由相信它遵循指数分布。我想估计分布参数 (lambda) 和一些置信度指示。置信区间或标准误差都可以。可悲的是,scipy.stats.expon.fit
似乎不允许这样做。这是一个例子,我将使用 lambda=1/120=0.008333 作为测试数据:
""" Generate test data"""
import scipy.stats
test_data = scipy.stats.expon(scale=120).rvs(size=3000)
""" Scipy.stats fit"""
fit = scipy.stats.expon.fit(test_data)
print("\nExponential parameters:", fit, " Specifically lambda: ", 1/fit[1], "\n")
# Exponential parameters: (0.0066790678905608875, 116.8376079908356) Specifically lambda: 0.008558887991599736
关于伽马分布数据的类似问题的答案建议使用GenericLikelihoodModel
模块statsmodels
。虽然我可以确认这对于 gamma 分布的数据非常有效,但它不适用于指数分布,因为优化显然会导致不可逆的 Hessian 矩阵。这是由于 Hessian 矩阵中的非有限元素或np.linalg.eigh
为 Hessian 矩阵生成非正特征值造成的。(这里的源代码;HessianInversionWarning 在类的fit
方法中引发LikelihoodModel
。)。
""" Statsmodel fit"""
from statsmodels.base.model import GenericLikelihoodModel
class Expon(GenericLikelihoodModel):
nparams = 2
def loglike(self, params):
return scipy.stats.expon.logpdf(self.endog, *params).sum()
res = Expon(test_data).fit(start_params=fit)
res.df_model = len(fit)
res.df_resid = len(test_data) - len(fit)
print(res.summary())
#Optimization terminated successfully.
# Current function value: 5.760785
# Iterations: 38
# Function evaluations: 76
#/usr/lib/python3.8/site-packages/statsmodels/tools/numdiff.py:352: RuntimeWarning: invalid value encountered in double_scalars
# hess[i, j] = (f(*((x + ee[i, :] + ee[j, :],) + args), **kwargs)
#/usr/lib/python3.8/site-packages/statsmodels/base/model.py:547: HessianInversionWarning: Inverting hessian failed, no bse or cov_params available
# warn('Inverting hessian failed, no bse or cov_params '
#/usr/lib/python3.8/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in greater
# return (a < x) & (x < b)
#/usr/lib/python3.8/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in less
# return (a < x) & (x < b)
#/usr/lib/python3.8/site-packages/scipy/stats/_distn_infrastructure.py:1912: RuntimeWarning: invalid value encountered in less_equal
# cond2 = cond0 & (x <= _a)
# Expon Results
#==============================================================================
#Dep. Variable: y Log-Likelihood: -17282.
#Model: Expon AIC: 3.457e+04
#Method: Maximum Likelihood BIC: 3.459e+04
#Date: Thu, 06 Aug 2020
#Time: 13:55:24
#No. Observations: 3000
#Df Residuals: 2998
#Df Model: 2
#==============================================================================
# coef std err z P>|z| [0.025 0.975]
#------------------------------------------------------------------------------
#par0 0.0067 nan nan nan nan nan
#par1 116.8376 nan nan nan nan nan
#==============================================================================
这似乎每次都会发生,因此它可能与指数分布的数据有关。
还有其他可能的方法吗?或者我可能在这里遗漏了什么或做错了什么?
编辑:事实证明,我做错了什么,即我错误地
test_data = scipy.stats.expon(120).rvs(size=3000)
代替
test_data = scipy.stats.expon(scale=120).rvs(size=3000)
并相应地查看 fit 元组的第一个元素,而我应该查看第二个元素。
结果,我考虑的另外两个选项(按照维基百科上描述的标准程序手动计算拟合和置信区间)并按照此答案scikits.bootstrap
中的建议使用实际上确实有效,并且是我将在一分钟内添加的解决方案的一部分不是问题。