Python中指数分布lambda参数置信区间的计算

Python中指数分布lambda参数置信区间的计算,python,statsmodels,confidence-interval,data-fitting,scipy.stats,Python,Statsmodels,Confidence Interval,Data Fitting,Scipy.stats,假设我有一个样本,我有理由相信它服从指数分布。我想估计分布参数(λ)和一些置信度指标。置信区间或标准误差都可以。遗憾的是,scipy.stats.expon.fit似乎不允许这样做。下面是一个示例,我将使用lambda=1/120=0.008333作为测试数据: """ Generate test data""" import scipy.stats test_data = scipy.stats.expon(scale=120).rv

假设我有一个样本,我有理由相信它服从指数分布。我想估计分布参数(λ)和一些置信度指标。置信区间或标准误差都可以。遗憾的是,
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 
建议使用
statsmodels
模块中的
GenericLikelihoodModel
。虽然我可以确认这对gamma分布的数据很有效,但对指数分布则不行,因为优化显然会导致不可逆的Hessian矩阵。这是由Hessian中的非有限元或由产生Hessian非正特征值的
np.linalg.eigh
得出的结果。()

而不是

test_data = scipy.stats.expon(scale=120).rvs(size=3000)
相应地,我在看fit元组的forst元素,而我应该在看第二个


因此,我考虑的另外两个选项()和使用scikits.bootstrap实际上是有效的,是我稍后添加的解决方案的一部分,而不是问题的一部分。

如编辑的问题中所述,问题的一部分是,我在创建样本时看到了错误的参数,然后又在拟合中看到了错误的参数

剩下的是,
scipy.stats.expon.fit
不提供计算置信度或错误的可能性,并且使用
statsmodels
模块中的
GenericLikelihoodModel
会因Hessian格式错误而失败

然而,有三种方法确实有效:

1。使用指数数据置信区间的简单推断程序,如

置信区间的计算:

""" Maximum likelihood 95% confidence"""
CI_distance = ML_BC_lambda * 1.96/(len(test_data)**0.5)
print("\nLambda with confidence intervals: {0:8f} +/- {1:8f}".format(ML_BC_lambda, CI_distance))
print("Confidence intervals: ({0:8f}, {1:9f})".format(ML_BC_lambda - CI_distance, ML_BC_lambda + CI_distance))

#Lambda with confidence intervals: 0.008556 +/- 0.000306
#Confidence intervals: (0.008249,  0.008862)
第二种选择是:此外,置信区间方程也应适用于由另一种方法产生的lambda估计值,例如来自
scipy.stats.expon.fit
的lambda估计值。(我认为
scipy.stats.expon.fit
中的拟合过程更可靠,但事实证明它实际上是一样的,没有偏差校正(见上文)

2。使用scikits进行引导。引导后续 这会产生一个
不稳定性警告:某些值为NaN;结果可能不稳定(所有值可能相等)
,因此对此应持怀疑态度

""" Bootstrapping with scikits"""
print("\n")
import scikits.bootstrap as boot
bootstrap_result = boot.ci(test_data, scipy.stats.expon.fit)
print(bootstrap_result)

#tmp/expon_fit_test.py:53: InstabilityWarning: Some values were NaN; results are probably unstable (all values were probably equal)
#  bootstrap_result = boot.ci(test_data, scipy.stats.expon.fit)
#[[6.67906789e-03 1.12615588e+02]
# [6.67906789e-03 1.21127091e+02]]
3。使用
rpy2

""" Maximum likelihood"""
import numpy as np
ML_lambda = 1 / np.mean(test_data)
print("\nML lambda: {0:8f}".format(ML_lambda))

#ML lambda: 0.008558

""" Bias corrected ML"""
ML_BC_lambda = ML_lambda - ML_lambda / (len(test_data) - 1)
print("\nML bias-corrected lambda: {0:8f}".format(ML_BC_lambda))

#ML bias-corrected lambda: 0.008556
""" Using r modules with rpy2"""
import rpy2.robjects as robjects
from rpy2.robjects.packages import importr
MASS = importr('MASS')
import rpy2.robjects.numpy2ri
rpy2.robjects.numpy2ri.activate()
rpy_fit = MASS.fitdistr(test_data, "exponential")
rpy_estimate = rpy_fit.rx("estimate")[0][0]
rpy_sd = rpy_fit.rx("sd")[0][0]
rpy_lower = rpy_estimate - 2*rpy_sd
rpy_upper = rpy_estimate + 2*rpy_sd
print("\nrpy2 fit: \nLambda={0:8f} +/- {1:8f}, CI: ({2:8f}, {3:8f})".format(rpy_estimate, rpy_sd, rpy_lower, rpy_upper))

#rpy2 fit: 
#Lambda=0.008558 +/- 0.000156, CI: (0.008246, 0.008871)

您已经找到了问题的解决方案,但这里有一个基于OpenTURNS的解决方案。我认为它依赖于引擎盖下的自举

OpenTURNS要求您重新调整数据的形状,以便清楚地看到我们处理的是3000个一维点,而不是单个3000维点

test_data = test_data.reshape(-1, 1)
剩下的就相当简单了

import openturns as ot

confidence_level = 0.9

params_ci = ot.ExponentialFactory().buildEstimator(test_data).getParameterDistribution().computeBilateralConfidenceInterval(confidence_level)

lambda_ci = [params_ci.getLowerBound()[0], params_ci.getUpperBound()[0]] 
# the index 0 means we are interested in the CI on lambda

print(lambda_ci)
我得到了以下输出(但这取决于随机种子):


我的第一个猜测是,估计“loc”时会出现问题,因为它转移了分布的支持。尝试修正loc=0,只估算lambda。@约瑟夫谢谢你的建议。事实上,我犯了更严重的错误,请看我的编辑。
""" Using r modules with rpy2"""
import rpy2.robjects as robjects
from rpy2.robjects.packages import importr
MASS = importr('MASS')
import rpy2.robjects.numpy2ri
rpy2.robjects.numpy2ri.activate()
rpy_fit = MASS.fitdistr(test_data, "exponential")
rpy_estimate = rpy_fit.rx("estimate")[0][0]
rpy_sd = rpy_fit.rx("sd")[0][0]
rpy_lower = rpy_estimate - 2*rpy_sd
rpy_upper = rpy_estimate + 2*rpy_sd
print("\nrpy2 fit: \nLambda={0:8f} +/- {1:8f}, CI: ({2:8f}, {3:8f})".format(rpy_estimate, rpy_sd, rpy_lower, rpy_upper))

#rpy2 fit: 
#Lambda=0.008558 +/- 0.000156, CI: (0.008246, 0.008871)
test_data = test_data.reshape(-1, 1)
import openturns as ot

confidence_level = 0.9

params_ci = ot.ExponentialFactory().buildEstimator(test_data).getParameterDistribution().computeBilateralConfidenceInterval(confidence_level)

lambda_ci = [params_ci.getLowerBound()[0], params_ci.getUpperBound()[0]] 
# the index 0 means we are interested in the CI on lambda

print(lambda_ci)
[0.008076302149561718, 0.008688296487447742]