predict.lm()如何计算置信区间和预测区间?

33

我进行了回归分析:

CopierDataRegression <- lm(V1~V2, data=CopierData1)

我的任务是获得给定 V2=6 的平均响应的90%置信区间和90%预测区间。

我使用了以下代码:

X6 <- data.frame(V2=6)
predict(CopierDataRegression, X6, se.fit=TRUE, interval="confidence", level=0.90)
predict(CopierDataRegression, X6, se.fit=TRUE, interval="prediction", level=0.90)

我得到了(87.3, 91.9)(74.5, 104.8),这似乎是正确的,因为PI应该更宽。

对于两者的输出,也包括了相同的se.fit = 1.39我不明白这个标准误差是什么。 PI的标准误差不应该比CI大吗? 我如何在R中找到这两个不同的标准误差? enter image description here


数据:

CopierData1 <- structure(list(V1 = c(20L, 60L, 46L, 41L, 12L, 137L, 68L, 89L, 
          4L, 32L, 144L, 156L, 93L, 36L, 72L, 100L, 105L, 131L, 127L, 57L, 
          66L, 101L, 109L, 74L, 134L, 112L, 18L, 73L, 111L, 96L, 123L, 
          90L, 20L, 28L, 3L, 57L, 86L, 132L, 112L, 27L, 131L, 34L, 27L, 
          61L, 77L), V2 = c(2L, 4L, 3L, 2L, 1L, 10L, 5L, 5L, 1L, 2L, 9L, 
          10L, 6L, 3L, 4L, 8L, 7L, 8L, 10L, 4L, 5L, 7L, 7L, 5L, 9L, 7L, 
          2L, 5L, 7L, 6L, 8L, 5L, 2L, 2L, 1L, 4L, 5L, 9L, 7L, 1L, 9L, 2L, 
          2L, 4L, 5L)), .Names = c("V1", "V2"),
          class = "data.frame", row.names = c(NA, -45L))

看一下 ?predict.lm,它说:*"se.fit: 预测均值的标准误差"。* "预测均值"听起来好像只适用于置信区间。如果你不想看到它,可以将 se.fit = FALSE - Gregor Thomas
谢谢。我想问的是,如何计算图片中的两个标准误差?这样我就可以验证计算并知道它们是如何推导出来的。 - Mitty
2个回答

78
指定 intervallevel 参数时,predict.lm 可以返回置信区间(CI)或预测区间(PI)。本答案展示如何在不设置这些参数的情况下获得 CI 和 PI。有两种方法:
  • 使用来自 predict.lm 的中间结果;
  • 从头开始做。
了解如何使用这两种方式可以全面了解预测过程。
请注意,我们仅涵盖 predict.lm 的默认情况下的 type =“response”。讨论 type =“terms” 超出了本答案的范围。

设置

为了帮助其他读者复制、粘贴和运行代码,我在此收集您的代码。我还更改了变量名称,使它们具有更清晰的含义。此外,我扩展了 newdat 来包括多个行,以显示我们的计算是“向量化”的。
dat <- structure(list(V1 = c(20L, 60L, 46L, 41L, 12L, 137L, 68L, 89L, 
          4L, 32L, 144L, 156L, 93L, 36L, 72L, 100L, 105L, 131L, 127L, 57L, 
          66L, 101L, 109L, 74L, 134L, 112L, 18L, 73L, 111L, 96L, 123L, 
          90L, 20L, 28L, 3L, 57L, 86L, 132L, 112L, 27L, 131L, 34L, 27L, 
          61L, 77L), V2 = c(2L, 4L, 3L, 2L, 1L, 10L, 5L, 5L, 1L, 2L, 9L, 
          10L, 6L, 3L, 4L, 8L, 7L, 8L, 10L, 4L, 5L, 7L, 7L, 5L, 9L, 7L, 
          2L, 5L, 7L, 6L, 8L, 5L, 2L, 2L, 1L, 4L, 5L, 9L, 7L, 1L, 9L, 2L, 
          2L, 4L, 5L)), .Names = c("V1", "V2"),
          class = "data.frame", row.names = c(NA, -45L))

lmObject <- lm(V1 ~ V2, data = dat)

newdat <- data.frame(V2 = c(6, 7))

以下是predict.lm的输出结果,稍后将与我们的手动计算进行比较。
predict(lmObject, newdat, se.fit = TRUE, interval = "confidence", level = 0.90)
#$fit
#        fit       lwr      upr
#1  89.63133  87.28387  91.9788
#2 104.66658 101.95686 107.3763
#
#$se.fit
#       1        2 
#1.396411 1.611900 
#
#$df
#[1] 43
#
#$residual.scale
#[1] 8.913508

predict(lmObject, newdat, se.fit = TRUE, interval = "prediction", level = 0.90)
#$fit
#        fit      lwr      upr
#1  89.63133 74.46433 104.7983
#2 104.66658 89.43930 119.8939
#
#$se.fit
#       1        2 
#1.396411 1.611900 
#
#$df
#[1] 43
#
#$residual.scale
#[1] 8.913508

使用predict.lm的中间结果

## use `se.fit = TRUE`
z <- predict(lmObject, newdat, se.fit = TRUE)
#$fit
#        1         2 
# 89.63133 104.66658 
#
#$se.fit
#       1        2 
#1.396411 1.611900 
#
#$df
#[1] 43
#
#$residual.scale
#[1] 8.913508

se.fit是什么?

z$se.fit是预测均值z$fit的标准误差,用于构建z$fit的置信区间。我们还需要自由度为z$df的t分布的分位数。

alpha <- 0.90  ## 90%
Qt <- c(-1, 1) * qt((1 - alpha) / 2, z$df, lower.tail = FALSE)
#[1] -1.681071  1.681071

## 90% confidence interval
CI <- z$fit + outer(z$se.fit, Qt)
colnames(CI) <- c("lwr", "upr")
CI
#        lwr      upr
#1  87.28387  91.9788
#2 101.95686 107.3763

我们可以看到,这与predict.lm(, interval = "confidence")相符。

PI的标准误差是多少?

PI比CI更宽,因为它考虑了残差方差:

variance_of_PI = variance_of_CI + variance_of_residual

请注意,这是逐点定义的。对于非加权线性回归(如您的示例),残差方差在各处相等(称为同方差性),它是 z$residual.scale ^ 2。因此,PI 的标准误差为:

se.PI <- sqrt(z$se.fit ^ 2 + z$residual.scale ^ 2)
#       1        2 
#9.022228 9.058082 

PI是这样构建的

PI <- z$fit + outer(se.PI, Qt)
colnames(PI) <- c("lwr", "upr")
PI
#       lwr      upr
#1 74.46433 104.7983
#2 89.43930 119.8939

我们可以看到这与 predict.lm(, interval = "prediction") 相符。

备注

如果您使用加权线性回归,情况会更加复杂,因为残差方差不是均等的,所以应该加权 z$residual.scale ^ 2。对于拟合值(即在使用 predict.lm 中的 type = "prediction" 时不设置 newdata),构建 PI 更容易,因为权重已知(在使用 lm 时必须通过 weight 参数提供)。对于外部预测(即将 newdata 传递给 predict.lm),predict.lm 希望您告诉它如何加权残差方差。您需要在 predict.lm 中使用参数 pred.varweights,否则您将收到来自 predict.lm 的警告,提示无法构建 PI 的信息不足。以下内容摘自 ?predict.lm:

 The prediction intervals are for a single observation at each case
 in ‘newdata’ (or by default, the data used for the fit) with error
 variance(s) ‘pred.var’.  This can be a multiple of ‘res.var’, the
 estimated value of sigma^2: the default is to assume that future
 observations have the same error variance as those used for
 fitting.  If ‘weights’ is supplied, the inverse of this is used as
 a scale factor.  For a weighted fit, if the prediction is for the
 original data frame, ‘weights’ defaults to the weights used for
 the model fit, with a warning since it might not be the intended
 result.  If the fit was weighted and ‘newdata’ is given, the
 default is to assume constant prediction variance, with a warning.
请注意,CI的构建不受回归类型影响。
从头开始做一切
基本上,我们想知道如何在z中获取fit、se.fit、df和residual.scale。
预测均值可以通过矩阵向量乘法Xp %*% b计算,其中Xp是线性预测矩阵,b是回归系数向量。
Xp <- model.matrix(delete.response(terms(lmObject)), newdat)
b <- coef(lmObject)
yh <- c(Xp %*% b)  ## c() reshape the single-column matrix to a vector
#[1]  89.63133 104.66658

我们可以看到这与z$fit相符。 yh的方差协方差为Xp %*% V %*% t(Xp),其中Vb的方差协方差矩阵,可以通过以下方式计算:

V <- vcov(lmObject)  ## use `vcov` function in R
#             (Intercept)         V2
# (Intercept)    7.862086 -1.1927966
# V2            -1.192797  0.2333733
yh的完整方差-协方差矩阵不需要计算点估计的CI或PI。我们只需要它的主对角线。因此,我们可以通过以下更有效的方式进行而不是执行diag(Xp %*% V %*% t(Xp))
var.fit <- rowSums((Xp %*% V) * Xp)  ## point-wise variance for predicted mean
#       1        2 
#1.949963 2.598222 

sqrt(var.fit)  ## this agrees with `z$se.fit`
#       1        2 
#1.396411 1.611900 

剩余自由度在拟合模型中很容易获得:

dof <- df.residual(lmObject)
#[1] 43

最后,为计算残差方差,请使用Pearson估计量:
sig2 <- c(crossprod(lmObject$residuals)) / dof
# [1] 79.45063

sqrt(sig2)  ## this agrees with `z$residual.scale`
#[1] 8.913508

注意

在加权回归的情况下,应按以下方式计算sig2

sig2 <- c(crossprod(sqrt(lmObject$weights) * lmObject$residuals)) / dof

附录:自编函数模仿 predict.lm

"从头开始做一切"中的代码已经整理成一个函数lm_predict,请参考这个问答:使用线性模型lm:如何获得预测值总和的预测方差


5

我不知道是否有快速提取预测区间标准误差的方法,但您总是可以反推出标准误差的区间(即使这不是非常优雅的方法):

m <- lm(V1 ~ V2, data = d)                                                                                                                                                                                                                

newdat <- data.frame(V2=6)                                                                                                                                                                                                                
tcrit <- qt(0.95, m$df.residual)                                                                                                                                                                                                          

a <- predict(m, newdat, interval="confidence", level=0.90)                                                                                                                                                                                
cat("CI SE", (a[1, "upr"] - a[1, "fit"]) / tcrit, "\n")                                                                                                                                                                                   

b <- predict(m, newdat, interval="prediction", level=0.90)                                                                                                                                                                                
cat("PI SE", (b[1, "upr"] - b[1, "fit"]) / tcrit, "\n") 

请注意,CI SE的值与se.fit中的值相同。

1
这个方法可行。我使用反推法计算了SE,使用公式89.63 + - t(0.95,43)xSE = Lower Bound,其中CI的下限为87.28,PI的下限为74.46。SE的CI为1.39,SE的PI为9.02。因此,预测区间的SE大于置信区间。但是,我仍然不明白为什么R中的输出结果在预测区间中列出了se.fit = 1.39。为什么它不列出9呢?谢谢! - Mitty
简单就是非常优雅的...而且也是练习基本理解的好方法。 - Mike M
在 tcrit <- qt(0.95, m$df.residual) 中,为什么使用 0.95 而不是 0.90?是因为这是单侧的吗?换句话说,假设我们正在寻找一个82%的置信区间,我们会使用qt(0.91, m$df.residual)吗? - MikeS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接