Як R обробляє пропущені значення в мкм?


32

Я хотів би регресувати вектор B проти кожного зі стовпців у матриці А. Це тривіально, якщо відсутні дані, але якщо матриця A містить відсутні значення, то моя регресія проти A обмежена, щоб включати лише рядки, де всі значення присутні ( поведінка na.omit за замовчуванням ). Це дає неправильні результати для стовпців, у яких відсутні дані. Я можу регресувати матрицю B стовпців проти окремих стовпців матриці A, але у мене є тисячі регресій, і це непомірно повільно і неелегантно. Функція na.exclude, здається, створена для цього випадку, але я не можу змусити її працювати. Що я тут роблю неправильно? Використовуючи R 2.13 на OSX, якщо це має значення.

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
Що ви маєте на увазі під "я можу обчислити кожен рядок окремо"?
chl

Вибачте, мав на увазі сказати "Я можу регресувати матрицю B стовпців проти стовпців у" окремо ", що означає одноразові виклики до lm. Відредаговано для відображення цього.
Девід Квіглі

1
Одноразові виклики до lm / регресії не є прекрасним способом робити регресію (йдеться за визначенням регресії, яка полягає у знаходженні часткового впливу кожного прогноктора на реакцію / результат, враховуючи стан інших змінні)
KarthikS

Відповіді:


23

Редагувати: я неправильно зрозумів ваше запитання. Є два аспекти:

а) na.omitі na.excludeобидва роблять випадкове вилучення щодо прогнозів та критеріїв. Вони відрізняються лише тим, що функції екстрактора люблять residuals()або fitted()будуть забивати свій висновок NAs для опущених випадків з na.exclude, таким чином, мають вихід такої ж довжини, як і вхідні змінні.

> 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) Справжня проблема полягає не в цій різниці між, na.omitі na.exclude, здається, ви не хочете видалити випадково випадки, які враховують змінні критерії, що і обидва.

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

Х+=(Х'Х)-1Х'Хβ^=Х+YН=ХХ+Y^=НYХY, тому немає можливості підібрати окремі регресії для кожного критерію. Ви можете спробувати уникнути накладних витрат lm(), зробивши щось відповідно до наступного:

> 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

Х+НQRYlm()


Це має сенс, враховуючи моє розуміння того, як повинен працювати на.exclude. Однак якщо ви зателефонуєте> X.both = cbind (X1, X2), а потім> dim (lm (X.both ~ Y, na.action = na.exclude) $ залишки), ви все одно отримаєте 94 залишки замість 97 та 97.
Девід Квіглі

Це вдосконалення, але якщо ви подивитеся на залишки (lm (X.both ~ Y, na.action = na.exclude)), ви побачите, що кожен стовпець має шість відсутніх значень, навіть незважаючи на відсутні значення у стовпці 1 X. обидва з різних зразків, ніж ті, що містяться у колонці 2. Отже, na.exclude зберігає форму матриці залишків, але під кришкою R, очевидно, лише регресує значення зі всіх рядків X.both. Можливо, це є вагомою статистичною причиною, але для мого застосування це проблема.
Девід Квіглі

@David Я неправильно зрозумів ваше запитання. Я думаю, що зараз я бачу вашу думку, і я відредагував свою відповідь, щоб вирішити її.
каракал

5

Я можу придумати два способи. Одне полягає в об'єднанні даних за допомогою, na.excludeа потім знову розділенні даних:

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)

Інший спосіб - використовувати dataаргумент і створити формулу.

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)

Якщо ви робите багато регресу, перший спосіб повинен бути швидшим, оскільки менше фонової магії виконується. Хоча якщо вам потрібні лише коефіцієнти та залишки, я пропоную використовувати lsfit, що набагато швидше, ніж lm. Другий спосіб трохи приємніший, але на моєму ноутбуці, намагаючись зробити резюме за результатом регресії, видається помилка. Я спробую побачити, чи це помилка.


Дякую, але lm (A.ex ~ B.ex) у вашому коді підходить 9 балів проти A1 (правильно) та 9 балів проти A2 (небажано). Є 10 вимірюваних точок як для B1, так і для A2; Я викидаю одну точку в регресії B1 проти A2, оскільки відповідна точка відсутня в A1. Якщо це просто "Як це працює", я можу це прийняти, але це не те, що я намагаюся зробити R, щоб зробити.
Девід Квіглі

@David, о, схоже, я неправильно зрозумів вашу проблему. Я викладу виправлення пізніше.
mpiktas

1

Наступний приклад показує, як робити прогнози та залишки, які відповідають вихідному фрейму даних (використовуючи параметр "na.action = na.exclude" в lm (), щоб вказати, що NA повинні розміщуватися в залишкових і прогнозованих векторах, де початковий кадр даних він також показує, як вказати, чи повинні передбачення включати лише спостереження, коли і пояснювальні, і залежні змінні були повними (тобто, суворо передбачувані прогнози) або спостереження, де пояснювальні змінні були повними, і, отже, можливе прогнозування Xb, ( тобто, включаючи позапробний прогноз для спостережень, які мали повні пояснювальні змінні, але у них відсутня залежна змінна).

Я використовую cbind, щоб додати прогнозовані та залишкові змінні до початкового набору даних.

## 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)))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.