web-dev-qa-db-fra.com

Comment Predict.lm () calcule-t-il l'intervalle de confiance et l'intervalle de prédiction?

J'ai couru une régression:

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

et ma tâche était d'obtenir un

  • 90% intervalle de confiance pour la réponse moyenne donnée V2=6 et 
  • 90% intervalle de prédiction lorsque V2=6.

J'ai utilisé le code suivant: 

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)

et j'ai (87.3, 91.9) et (74.5, 104.8) qui semble être correct puisque le PI devrait être plus large.

La sortie pour les deux incluait également se.fit = 1.39 qui était identique. Je ne comprends pas ce qu'est cette erreur standard. L'erreur type ne devrait-elle pas être plus grande pour l'IP par rapport à l'EC? Comment trouver ces deux erreurs types différentes dans R? enter image description here


Les données:

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

Lorsque vous spécifiez les arguments interval et level, predict.lm peut renvoyer un intervalle de confiance (IC) ou un intervalle de prédiction (PI). Cette réponse montre comment obtenir des CI et des PI sans définir ces arguments. Il y a deux manières:

  • utilisez le résultat intermédiaire de predict.lm;
  • tout faire à partir de zéro.

En sachant travailler avec les deux méthodes, vous comprendrez parfaitement la procédure de prévision.

Notez que nous ne couvrirons que le cas type = "response" (par défaut) pour predict.lm. La discussion sur type = "terms" déborde le cadre de cette réponse.


Installer

Je rassemble votre code ici pour aider les autres lecteurs à copier, coller et exécuter. Je change également les noms des variables afin qu’elles aient un sens plus clair. De plus, j'élargis la newdat pour inclure plus d'une ligne, pour montrer que nos calculs sont "vectorisés".

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

Ce qui suit est la sortie de predict.lm, à comparer avec nos calculs manuels ultérieurement.

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

Utiliser le résultat intermédiaire de 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

Qu'est-ce que se.fit?

z$se.fit est l'erreur standard de la moyenne prévue z$fit, utilisée pour construire un CI pour z$fit. Nous avons également besoin de quantiles de la distribution t avec un degré de liberté 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

Nous voyons que cela est en accord avec predict.lm(, interval = "confidence").

Quelle est l'erreur type pour PI?

PI est plus large que CI, car il rend compte de la variance résiduelle:

variance_of_PI = variance_of_CI + variance_of_residual

Notez que ceci est défini au point. Pour une régression linéaire non pondérée (comme dans votre exemple), la variance résiduelle est égale partout (connue sous le nom de homoscédasticité) et correspond à z$residual.scale ^ 2. Ainsi, l'erreur standard pour PI est

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

et PI est construit comme

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

Nous voyons que cela est en accord avec predict.lm(, interval = "prediction").

remarque

Les choses sont plus compliquées si vous avez une régression linéaire en poids, où la variance résiduelle n'est pas égale partout, de sorte que z$residual.scale ^ 2 doit être pondéré. Il est plus facile de construire des PI pour les valeurs ajustées (autrement dit, vous ne définissez pas newdata lorsque vous utilisez type = "prediction" dans predict.lm), car les poids sont connus (vous devez l'avoir fourni via l'argument weight lorsque vous utilisez lm). Pour les prédictions hors échantillon (c'est-à-dire que vous passez newdata à predict.lm), predict.lm s'attend à ce que vous lui indiquiez comment la variance résiduelle doit être pondérée. Vous devez utiliser l'argument pred.var ou weights dans predict.lm, sinon vous recevez un avertissement de predict.lm indiquant des informations insuffisantes pour la construction de PI. Les éléments suivants sont extraits de ?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.

Notez que la construction de CI n'est pas affectée par le type de régression.


Tout faire à partir de zéro

En gros, nous voulons savoir comment obtenir fit, se.fit, df et residual.scale dans z.

La moyenne prédite peut être calculée par une multiplication matrice-vecteur Xp %*% b, où Xp est la matrice de prédicteur linéaire et b est le vecteur de coefficient de régression.

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

Et nous voyons que cela est en accord avec z$fit. La variance-covariance pour yh est Xp %*% V %*% t(Xp), où V est la matrice de variance-covariance de b qui peut être calculée par

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

La matrice de variance-covariance complète de yh n'est pas nécessaire pour calculer l'IC ou l'IP point par point. Nous avons seulement besoin de sa diagonale principale. Donc, au lieu de faire diag(Xp %*% V %*% t(Xp)), nous pouvons le faire plus efficacement via

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 

Le degré de liberté résiduel est facilement disponible dans le modèle monté:

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

Enfin, pour calculer la variance résiduelle, utilisez l’estimateur de Pearson:

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

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

remarque

Notez qu'en cas de régression pondérée, sig2 doit être calculé comme suit:

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

Annexe: une fonction auto-écrite qui imite predict.lm

Le code dans "Tout faire à partir de zéro" a été clairement organisé en une fonction lm_predict dans ce modèle de questions-réponses: modèle linéaire avec lm: comment obtenir la variance de prédiction de la somme des valeurs prédites .

31
李哲源

Je ne sais pas s'il existe un moyen rapide d'extraire l'erreur standard pour l'intervalle de prédiction, mais vous pouvez toujours effectuer une résolution en arrière des intervalles pour le SE (même si ce n'est pas une approche très élégante):

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

Notez que le CI SE a la même valeur que celle de se.fit

2
MAB