wake-up-neo.net

Wie berechnet predict.lm () das Konfidenzintervall und das Vorhersageintervall?

Ich habe eine Regression ausgeführt:

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

und meine Aufgabe war es, eine

  • 90% Konfidenzintervall für die gemittelte Antwort V2=6 und 
  • 90% Vorhersageintervall wenn V2=6.

Ich habe folgenden Code verwendet: 

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)

und ich bekam (87.3, 91.9) und (74.5, 104.8) was scheinbar richtig ist, da der PI breiter sein sollte.

Die Ausgabe für beide enthielt ebenfalls se.fit = 1.39, was derselbe war. Ich verstehe nicht, was dieser Standardfehler ist. Sollte der Standardfehler für den PI nicht größer sein als für das CI? Wie finde ich diese zwei unterschiedlichen Standardfehler in R? enter image description here


Daten:

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))
8
Mitty

Wenn Sie das Argument interval und level angeben, kann predict.lm das Konfidenzintervall (CI) oder das Vorhersageintervall (PI) zurückgeben. Diese Antwort zeigt, wie Sie CI und PI erhalten, ohne diese Argumente festzulegen. Es gibt zwei Möglichkeiten:

  • verwenden Sie das Ergebnis der mittleren Stufe aus predict.lm;
  • mach alles von vorne.

Wenn Sie wissen, wie Sie mit beiden Methoden arbeiten, erhalten Sie ein gründliches Verständnis des Vorhersageverfahrens.

Beachten Sie, dass wir nur den Fall type = "response" (Standard) für predict.lm behandeln. Die Diskussion von type = "terms" geht über den Rahmen dieser Antwort hinaus.


Konfiguration

Ich sammle Ihren Code hier, um anderen Lesern beim Kopieren, Einfügen und Ausführen zu helfen. Ich ändere auch Variablennamen, damit sie klarere Bedeutungen haben. Außerdem erweitere ich die Variable newdat, um mehr als eine Zeile aufzunehmen, um zu zeigen, dass unsere Berechnungen "vektorisiert" sind.

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

Das Folgende ist die Ausgabe von predict.lm, die später mit unseren manuellen Berechnungen verglichen werden soll.

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

Ergebnis der mittleren Stufe von predict.lm verwenden

## 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

Was ist se.fit?

z$se.fit ist der Standardfehler des vorhergesagten Mittelwerts z$fit, der zur Erstellung des CI für z$fit verwendet wird. Wir brauchen auch Quantile der T-Verteilung mit einem Freiheitsgrad z$df.

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

Wir sehen, dass dies mit predict.lm(, interval = "confidence") übereinstimmt.

Was ist der Standardfehler für PI?

PI ist breiter als CI, da es die Restabweichung berücksichtigt:

variance_of_PI = variance_of_CI + variance_of_residual

Beachten Sie, dass dies punktweise definiert ist. Bei einer nicht gewichteten linearen Regression (wie in Ihrem Beispiel) ist die Restvarianz überall gleich (bekannt als Homoskedastizität) und es ist z$residual.scale ^ 2. Der Standardfehler für PI ist also

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

und PI ist als aufgebaut

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

Wir sehen, dass dies mit predict.lm(, interval = "prediction") übereinstimmt.

Anmerkung

Die Dinge sind komplizierter, wenn Sie eine lineare Gewichtungsregression haben, bei der die Restvarianz nicht überall gleich ist, so dass z$residual.scale ^ 2 gewichtet werden sollte. Es ist einfacher, PI für angepasste Werte zu erstellen (d. H. Sie setzen newdata nicht, wenn Sie type = "prediction" in predict.lm verwenden), da die Gewichte bekannt sind (Sie müssen sie bei Verwendung von weight über das Argument lm angegeben haben). Für die Out-of-Sample-Vorhersage (dh Sie übergeben eine newdata an predict.lm), erwartet predict.lm, dass Sie sagen, wie die Restvarianz gewichtet werden soll. Sie müssen entweder das Argument pred.var oder weights in predict.lm verwenden. Andernfalls erhalten Sie eine Warnung von predict.lm, die unzureichende Informationen zum Erstellen von PI beklagt. Folgendes wird aus ?predict.lm zitiert:

 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.

Beachten Sie, dass die Konstruktion von CI nicht von der Art der Regression beeinflusst wird.


Mach alles von Grund auf

Grundsätzlich möchten wir wissen, wie man fit, se.fit, df und residual.scale in z erhält.

Der vorhergesagte Mittelwert kann durch eine Matrix-Vektor-Multiplikation Xp %*% b berechnet werden, wobei Xp die lineare Prädiktormatrix und b der Regressionskoeffizientenvektor ist.

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

Und wir sehen, dass dies mit z$fit übereinstimmt. Die Varianz-Kovarianz für yh ist Xp %*% V %*% t(Xp), wobei V die Varianz-Kovarianzmatrix von b ist, die von berechnet werden kann

V <- vcov(lmObject)  ## use `vcov` function in R
#             (Intercept)         V2
# (Intercept)    7.862086 -1.1927966
# V2            -1.192797  0.2333733

Die vollständige Varianz-Kovarianz-Matrix von yh ist nicht erforderlich, um punktweise CI oder PI zu berechnen. Wir brauchen nur die Hauptdiagonale. Anstatt diag(Xp %*% V %*% t(Xp)) zu tun, können wir dies effizienter über tun

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 

Der Restfreiheitsgrad ist im eingebauten Modell leicht verfügbar:

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

Verwenden Sie zum Berechnen der Residualvarianz den Pearson-Schätzer:

sig2 <- c(crossprod(lmObject$residuals)) / dof
# [1] 79.45063

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

Anmerkung

Beachten Sie, dass im Falle einer gewichteten Regression sig2 als berechnet werden sollte

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

Anhang: Eine selbstgeschriebene Funktion, die predict.lm nachahmt

Der Code in "Alles neu erstellen" wurde in dieser Q & A-Funktion in einer Funktion lm_predict sauber organisiert: lineares Modell mit lm: So erhalten Sie die Vorhersagevarianz der Summe der vorhergesagten Werte .

31
李哲源

Ich weiß nicht, ob es einen schnellen Weg gibt, den Standardfehler für das Vorhersageintervall zu extrahieren, aber Sie können die Intervalle für die SE immer rückgängig machen (auch wenn es nicht sehr elegant ist):

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

Beachten Sie, dass der CI-SE derselbe Wert aus se.fit ist. 

2
MAB