Logistic回归statsmodels的概率预测置信区间

时间:2017-11-21 13:54:43

标签: python logistic-regression statsmodels confidence-interval

我试图从统计学习简介重新创建一个情节,而我却无法弄清楚如何计算概率预测的置信区间。具体来说,我试图重新创建该图的右侧面板(figure 7.1),该右侧面板基于具有相关95%置信区间的4度多项式来预测工资> 250的概率。如果有人关心,工资数据为here

我可以使用以下代码预测和绘制预测概率

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)

但我对如何计算预测概率的置信区间感到茫然。我已经考虑过多次引导数据以获得每个年龄的概率分布,但我知道有一种更容易的方法,这是我无法掌握的。

我有估计的系数协方差矩阵和与每个估计系数相关的标准误差。如果给出这些信息,我将如何计算置信区间,如上图右侧面板所示?

谢谢!

2 个答案:

答案 0 :(得分:12)

您可以使用delta method查找预测概率的近似方差。即,

var(proba) = np.dot(np.dot(gradient.T, cov), gradient)

其中gradient是模型系数预测概率导数的向量,cov是系数的协方差矩阵。

Delta方法被证明可以渐近地用于所有最大似然估计。但是,如果你有一个小的训练样本,渐近方法可能效果不好,你应该考虑自举。

以下是将delta方法应用于逻辑回归的玩具示例:

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()

它绘制了以下精美图片: enter image description here

对于您的示例,代码将是

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()

它会给出以下图片

enter image description here

看起来非常像一只内有大象的蟒蛇。

您可以将其与bootstrap估算值进行比较:

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()

enter image description here

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()

所以他们得到了不同的间隔:

enter image description here

这些方法会产生如此不同的结果,因为它们假设不同的东西(预测概率和对数概率)正常分布。也就是说,delta方法假设预测的概率是正常的,并且在书中,对数概率是正常的。实际上,它们在有限样本中都不是正常的,但它们都收敛于无限样本中,但它们的方差同时收敛于零。最大似然估计对重新参数化不敏感,但它们的估计分布是,这就是问题所在。

答案 1 :(得分:0)

在statsmodels Logit()。fit()对象顶部,这是一种用于计算拟合('mean_se')和单个观测值('obs_se')的标准误差('se')的指导性高效方法( 'fit'),与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

A figure similar to the one in the book ISLR

阴影区域表示拟合和单次观察的95%置信区间。

非常欢迎有改进的想法。