In che modo R gestisce i valori mancanti in lm?


32

Vorrei regredire un vettore B contro ciascuna delle colonne in una matrice A. Questo è banale se non ci sono dati mancanti, ma se la matrice A contiene valori mancanti, la mia regressione contro A è limitata per includere solo le righe in cui tutti sono presenti valori (il comportamento predefinito na.omit ). Ciò produce risultati errati per le colonne senza dati mancanti. Posso regredire la matrice di colonne B rispetto alle singole colonne della matrice A, ma ho migliaia di regressioni da fare, e questo è proibitivamente lento e inelegante. La funzione na.exclude sembra essere progettata per questo caso, ma non riesco a farlo funzionare. Cosa sto facendo di sbagliato qui? Utilizzando R 2.13 su OSX, se è importante.

A = matrix(1:20, nrow=10, ncol=2)
B = matrix(1:10, nrow=10, ncol=1)
dim(lm(A~B)$residuals)
# [1] 10 2 (the expected 10 residual values)

# Missing value in first column; now we have 9 residuals
A[1,1] = NA  
dim(lm(A~B)$residuals)
#[1]  9 2 (the expected 9 residuals, given na.omit() is the default)

# Call lm with na.exclude; still have 9 residuals
dim(lm(A~B, na.action=na.exclude)$residuals)
#[1]  9 2 (was hoping to get a 10x2 matrix with a missing value here)

A.ex = na.exclude(A)
dim(lm(A.ex~B)$residuals)
# Throws an error because dim(A.ex)==9,2
#Error in model.frame.default(formula = A.ex ~ B, drop.unused.levels = TRUE) : 
#  variable lengths differ (found for 'B')

1
Cosa intendi con "Posso calcolare ogni riga singolarmente"?
chl

Scusate, intendevo dire "Posso regredire la matrice di colonne B rispetto alle colonne in A individualmente", il che significa che chiamate one-to-time a lm. Modificato per riflettere questo.
David Quigley,

1
Le chiamate una tantum alla lm / regressione non sono un ottimo modo per fare regressione (andando dalla definizione di regressione, che è quella di trovare l'effetto parziale di ciascun predittore su una risposta / risultato dato lo stato dell'altro variabili)
KarthikS,

Risposte:


23

Modifica: ho frainteso la tua domanda. Ci sono due aspetti:

a) na.omited na.excludeentrambi effettuano la cancellazione caso per caso sia rispetto ai predittori che ai criteri. Differiscono solo per il fatto che funzioni dell'estrattore come residuals()o fitted()riempiranno il loro output con NAs per i casi omessi na.exclude, con un output della stessa lunghezza delle variabili di input.

> N    <- 20                               # generate some data
> y1   <- rnorm(N, 175, 7)                 # criterion 1
> y2   <- rnorm(N,  30, 8)                 # criterion 2
> x    <- 0.5*y1 - 0.3*y2 + rnorm(N, 0, 3) # predictor
> y1[c(1, 3,  5)] <- NA                    # some NA values
> y2[c(7, 9, 11)] <- NA                    # some other NA values
> Y    <- cbind(y1, y2)                    # matrix for multivariate regression
> fitO <- lm(Y ~ x, na.action=na.omit)     # fit with na.omit
> dim(residuals(fitO))                     # use extractor function
[1] 14  2

> fitE <- lm(Y ~ x, na.action=na.exclude)  # fit with na.exclude
> dim(residuals(fitE))                     # use extractor function -> = N
[1] 20  2

> dim(fitE$residuals)                      # access residuals directly
[1] 14  2

b) Il vero problema non è con questa differenza tra na.omite na.exclude, non sembri voler cancellare caso per caso che tenga conto delle variabili di criterio, cosa che entrambi fanno.

> X <- model.matrix(fitE)                  # design matrix
> dim(X)                                   # casewise deletion -> only 14 complete cases
[1] 14  2

I risultati della regressione dipendono dalle matrici (pseudoinverso della matrice di progettazione , coefficienti ) e il cappello matrice , valori adattati ). Se non si desidera la cancellazione caso per caso, è necessaria una matrice progettazione diversa per ogni colonna di , quindi non è possibile aggirare regressioni separate per ciascun criterio. Puoi provare a evitare il sovraccarico di fare qualcosa in linea con quanto segue: X β = X + Y H = X X + Y = H Y X YX+=(XX)1XXβ^=X+YH=XX+Y^=HYXYlm()

> Xf <- model.matrix(~ x)                    # full design matrix (all cases)
# function: manually calculate coefficients and fitted values for single criterion y
> getFit <- function(y) {
+     idx   <- !is.na(y)                     # throw away NAs
+     Xsvd  <- svd(Xf[idx , ])               # SVD decomposition of X
+     # get X+ but note: there might be better ways
+     Xplus <- tcrossprod(Xsvd$v %*% diag(Xsvd$d^(-2)) %*% t(Xsvd$v), Xf[idx, ])
+     list(coefs=(Xplus %*% y[idx]), yhat=(Xf[idx, ] %*% Xplus %*% y[idx]))
+ }

> res <- apply(Y, 2, getFit)    # get fits for each column of Y
> res$y1$coefs
                   [,1]
(Intercept) 113.9398761
x             0.7601234

> res$y2$coefs
                 [,1]
(Intercept) 91.580505
x           -0.805897

> coefficients(lm(y1 ~ x))      # compare with separate results from lm()
(Intercept)           x 
113.9398761   0.7601234 

> coefficients(lm(y2 ~ x))
(Intercept)           x 
  91.580505   -0.805897

Nota che potrebbero esserci modi numericamente migliori per caculare e , puoi invece controllare una decomposizione . L'approccio SVD è spiegato qui su SE . Non ho cronometrato l'approccio sopra con grandi matrici contro l'utilizzo effettivo . H Q R YX+HQRYlm()


Ciò ha senso data la mia comprensione di come dovrebbe funzionare na.exclude. Tuttavia, se chiami> X.both = cbind (X1, X2) e quindi> dim (lm (X.both ~ Y, na.action = na.exclude) $ residuals) otterrai comunque 94 residui, anziché 97 e 97.
David Quigley,

Questo è un miglioramento, ma se guardi i residui (lm (X.both ~ Y, na.action = na.exclude)), vedi che ogni colonna ha sei valori mancanti, anche se i valori mancanti nella colonna 1 di X. entrambi provengono da campioni diversi da quelli della colonna 2. Quindi na.exclude sta conservando la forma della matrice dei residui, ma sotto il cofano R apparentemente sta solo regredendo con i valori presenti in tutte le file di X.both. Potrebbe esserci una buona ragione statistica per questo, ma per la mia applicazione è un problema.
David Quigley,

@David Avevo frainteso la tua domanda. Penso di vedere ora il tuo punto e ho modificato la mia risposta per risolverlo.
Caracal,

5

Posso pensare a due modi. Uno è combinare i dati utilizzare na.excludee quindi separare nuovamente i dati:

A = matrix(1:20, nrow=10, ncol=2)
colnames(A) <- paste("A",1:ncol(A),sep="")

B = matrix(1:10, nrow=10, ncol=1)
colnames(B) <- paste("B",1:ncol(B),sep="")

C <- cbind(A,B)

C[1,1] <- NA
C.ex <- na.exclude(C)

A.ex <- C[,colnames(A)]
B.ex <- C[,colnames(B)]

lm(A.ex~B.ex)

Un altro modo è usare l' dataargomento e creare una formula.

Cd <- data.frame(C)
fr <- formula(paste("cbind(",paste(colnames(A),collapse=","),")~",paste(colnames(B),collapse="+"),sep=""))

lm(fr,data=Cd)

Cd[1,1] <-NA

lm(fr,data=Cd,na.action=na.exclude)

Se stai facendo molta regressione, il primo modo dovrebbe essere più veloce, poiché viene eseguita meno magia di sottofondo. Anche se hai bisogno solo di coefficienti e residui, ti suggerisco di usare lsfit, che è molto più veloce di lm. Il secondo modo è un po 'più carino, ma sul mio laptop cercando di fare un riepilogo sulla regressione risultante genera un errore. Proverò a vedere se questo è un bug.


Grazie, ma lm (A.ex ~ B.ex) nel tuo codice misura 9 punti contro A1 (corretto) e 9 punti contro A2 (indesiderato). Ci sono 10 punti misurati sia per B1 che per A2; Sto gettando un punto nella regressione di B1 contro A2 perché il punto corrispondente manca in A1. Se questo è solo il modo in cui funziona, posso accettarlo, ma non è quello che sto cercando di far fare a R.
David Quigley,

@ David, oh, sembra che abbia frainteso il tuo problema. Pubblicherò la correzione più tardi.
mpiktas,

1

L'esempio seguente mostra come effettuare previsioni e residui conformi al frame di dati originale (utilizzando l'opzione "na.action = na.exclude" in lm () per specificare che i NA devono essere inseriti nei vettori residui e di previsione in cui il frame di dati originale aveva valori mancanti. Mostra anche come specificare se le previsioni dovrebbero includere solo osservazioni in cui le variabili esplicative e dipendenti erano complete (vale a dire, previsioni strettamente nel campione) o osservazioni in cui le variabili esplicative erano complete, e quindi la previsione Xb è possibile ( vale a dire, inclusa la previsione fuori campione per le osservazioni che avevano variabili esplicative complete ma che mancavano della variabile dipendente).

Uso cbind per aggiungere le variabili previste e residue al set di dati originale.

## Set up data with a linear model
N <- 10
NXmissing <- 2 
X <- runif(N, 0, 10)
Y <- 6 + 2*X + rnorm(N, 0, 1)
## Put in missing values (missing X, missing Y, missing both)
X[ sample(1:N , NXmissing) ] <- NA
Y[ sample(which(is.na(X)), 1)]  <- NA
Y[ sample(which(!is.na(X)), 1)]  <- NA
(my.df <- data.frame(X,Y))

## Run the regression with na.action specified to na.exclude
## This puts NA's in the residual and prediction vectors
my.lm  <- lm( Y ~ X, na.action=na.exclude, data=my.df)

## Predict outcome for observations with complete both explanatory and
## outcome variables, i.e. observations included in the regression
my.predict.insample  <- predict(my.lm)

## Predict outcome for observations with complete explanatory
## variables.  The newdata= option specifies the dataset on which
## to apply the coefficients
my.predict.inandout  <- predict(my.lm,newdata=my.df)

## Predict residuals 
my.residuals  <- residuals(my.lm)

## Make sure that it binds correctly
(my.new.df  <- cbind(my.df,my.predict.insample,my.predict.inandout,my.residuals))

## or in one fell swoop

(my.new.df  <- cbind(my.df,yhat=predict(my.lm),yhato=predict(my.lm,newdata=my.df),uhat=residuals(my.lm)))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.