Python logistic回归统计模型概率预测的置信区间
我正试图根据《统计学习导论》重新创建一个图,但我很难弄清楚如何计算概率预测的置信区间。具体地说,我试图重新创建这个图()的右侧面板,该面板根据年龄的4次多项式预测工资>250的概率,相关的95%置信区间。如果有人在乎的话,工资数据就是 我可以用下面的代码预测和绘制预测的概率Python logistic回归统计模型概率预测的置信区间,python,logistic-regression,statsmodels,confidence-interval,Python,Logistic Regression,Statsmodels,Confidence Interval,我正试图根据《统计学习导论》重新创建一个图,但我很难弄清楚如何计算概率预测的置信区间。具体地说,我试图重新创建这个图()的右侧面板,该面板根据年龄的4次多项式预测工资>250的概率,相关的95%置信区间。如果有人在乎的话,工资数据就是 我可以用下面的代码预测和绘制预测的概率 import pandas as pd import numpy as np import matplotlib.pyplot as plt import statsmodels.api as sm from sklearn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from sklearn.preprocessing import PolynomialFeatures
wage = pd.read_csv('../../data/Wage.csv', index_col=0)
wage['wage250'] = 0
wage.loc[wage['wage'] > 250, 'wage250'] = 1
poly = Polynomialfeatures(degree=4)
age = poly.fit_transform(wage['age'].values.reshape(-1, 1))
logit = sm.Logit(wage['wage250'], age).fit()
age_range_poly = poly.fit_transform(np.arange(18, 81).reshape(-1, 1))
y_proba = logit.predict(age_range_poly)
plt.plot(age_range_poly[:, 1], y_proba)
但是我不知道预测概率的置信区间是如何计算的。我已经考虑过多次引导数据,以获得每个年龄段的概率分布,但我知道有一种更简单的方法,这是我无法掌握的
我有估计系数协方差矩阵和与每个估计系数相关的标准误差。在给定这些信息的情况下,如何计算上图右侧面板所示的置信区间
谢谢 您可以使用来查找预测概率的近似方差。即
var(proba) = np.dot(np.dot(gradient.T, cov), gradient)
其中,gradient
是模型系数预测概率的导数向量,cov
是系数的协方差矩阵
Delta方法被证明是渐近工作的所有最大似然估计。但是,如果你有一个小的训练样本,渐近方法可能不能很好地工作,你应该考虑引导。
下面是一个将delta方法应用于logistic回归的示例:
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt
# generate data
np.random.seed(1)
x = np.arange(100)
y = (x * 0.5 + np.random.normal(size=100,scale=10)>30)
# estimate the model
X = sm.add_constant(x)
model = sm.Logit(y, X).fit()
proba = model.predict(X) # predicted probability
# estimate confidence interval for predicted probabilities
cov = model.cov_params()
gradient = (proba * (1 - proba) * X.T).T # matrix of gradients for each observation
std_errors = np.array([np.sqrt(np.dot(np.dot(g, cov), g)) for g in gradient])
c = 1.96 # multiplier for confidence interval
upper = np.maximum(0, np.minimum(1, proba + std_errors * c))
lower = np.maximum(0, np.minimum(1, proba - std_errors * c))
plt.plot(x, proba)
plt.plot(x, lower, color='g')
plt.plot(x, upper, color='g')
plt.show()
它描绘了以下美好的画面:
对于您的示例,代码是
proba = logit.predict(age_range_poly)
cov = logit.cov_params()
gradient = (proba * (1 - proba) * age_range_poly.T).T
std_errors = np.array([np.sqrt(np.dot(np.dot(g, cov), g)) for g in gradient])
c = 1.96
upper = np.maximum(0, np.minimum(1, proba + std_errors * c))
lower = np.maximum(0, np.minimum(1, proba - std_errors * c))
plt.plot(age_range_poly[:, 1], proba)
plt.plot(age_range_poly[:, 1], lower, color='g')
plt.plot(age_range_poly[:, 1], upper, color='g')
plt.show()
它会给出下面的图片
看起来很像一条里面有大象的蟒蛇
您可以将其与引导估计值进行比较:
preds = []
for i in range(1000):
boot_idx = np.random.choice(len(age), replace=True, size=len(age))
model = sm.Logit(wage['wage250'].iloc[boot_idx], age[boot_idx]).fit(disp=0)
preds.append(model.predict(age_range_poly))
p = np.array(preds)
plt.plot(age_range_poly[:, 1], np.percentile(p, 97.5, axis=0))
plt.plot(age_range_poly[:, 1], np.percentile(p, 2.5, axis=0))
plt.show()
delta方法和bootstrap的结果看起来几乎相同
然而,这本书的作者走了第三条路。他们利用这样一个事实
proba=np.exp(np.dot(x,params))/(1+np.exp(np.dot(x,params)))
计算线性部分的置信区间,然后使用logit函数进行变换
xb = np.dot(age_range_poly, logit.params)
std_errors = np.array([np.sqrt(np.dot(np.dot(g, cov), g)) for g in age_range_poly])
upper_xb = xb + c * std_errors
lower_xb = xb - c * std_errors
upper = np.exp(upper_xb) / (1 + np.exp(upper_xb))
lower = np.exp(lower_xb) / (1 + np.exp(lower_xb))
plt.plot(age_range_poly[:, 1], upper)
plt.plot(age_range_poly[:, 1], lower)
plt.show()
所以他们得到了发散间隔:
这些方法产生如此不同的结果,因为它们假设不同的事物(预测概率和对数概率)正态分布。也就是说,delta方法假设预测的概率是正常的,在书中,对数概率是正常的。事实上,它们在有限样本中都不是正态的,但在无限样本中它们都收敛到,但它们的方差同时收敛到零。最大似然估计对重新参数化不敏感,但它们的估计分布是不敏感的,这就是问题所在。这里有一个有指导意义的有效方法来计算statsmodels Logit()对象(“fit”)上拟合('mean_se')和单次观测('obs_se')的标准误差('se'),与《ISLR》一书中的方法和David Dale答案中的最后一种方法相同:
fit_mean = fit.model.exog.dot(fit.params)
fit_mean_se = ((fit.model.exog*fit.model.exog.dot(fit.cov_params())).sum(axis=1))**0.5
fit_obs_se = ( ((fit.model.endog-fit_mean).std(ddof=fit.params.shape[0]))**2 + \
fit_mean_se**2 )**0.5
阴影区域表示拟合和单次观察的95%置信区间
欢迎提出改进意见。回答得很好,大卫,谢谢!偏离的置信区间真的让我大吃一惊。@DavidDale回答得很好,但如果你澄清哪种方法假设预测概率为正态分布(增量法),哪种方法假设对数概率为正态分布(转换法,即你显示的最后一个图),那就更好了.你好,大卫,回答得很好-我试图用Sklearn.LogisticRecession重现你的结果,但是predict_proba的结果不同-你为什么这么认为?你好,大卫,你用线性部分的置信区间计算的结果将给我们反应的预测区间?或平均响应的置信区间?如果它给出了置信区间,我们如何计算预测区间?我计算平均响应的置信区间。它是二元分类,因此预测区间总是{0}、{1}或[0,1]。我认为这样的间隔没有多大意义。