Làm thế nào để R xử lý các giá trị thiếu trong lm?


32

Tôi muốn hồi quy một vectơ B đối với từng cột trong ma trận A. Đây là chuyện nhỏ nếu không có dữ liệu bị thiếu, nhưng nếu ma trận A chứa các giá trị bị thiếu, thì hồi quy của tôi đối với A bị ràng buộc chỉ bao gồm các hàng trong đó tất cả các giá trị có mặt ( hành vi na.omit mặc định ). Điều này tạo ra kết quả không chính xác cho các cột không có dữ liệu bị thiếu. Tôi có thể hồi quy ma trận cột B so với các cột riêng lẻ của ma trận A, nhưng tôi có hàng ngàn hồi quy để thực hiện và điều này rất chậm và không phù hợp. Hàm na.exclude dường như được thiết kế cho trường hợp này, nhưng tôi không thể làm cho nó hoạt động. Tôi làm gì sai ở đây? Sử dụng R 2.13 trên OSX, nếu có vấn đề.

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
Ý bạn là gì khi "Tôi có thể tính toán từng hàng riêng lẻ"?
chl

Xin lỗi, có nghĩa là nói "Tôi có thể hồi quy ma trận cột B so với các cột trong A", nghĩa là các cuộc gọi một lần đến lm. Chỉnh sửa để phản ánh điều này.
David Quigley

1
Các cuộc gọi một lần đến lm / hồi quy không phải là một cách hay để thực hiện hồi quy (theo định nghĩa của hồi quy, đó là tìm hiệu ứng từng phần của từng yếu tố dự đoán đối với phản ứng / kết quả do trạng thái khác biến)
KarthikS

Câu trả lời:


23

Chỉnh sửa: Tôi hiểu nhầm câu hỏi của bạn. Có hai khía cạnh:

a) na.omitna.excludecả hai đều xóa casewise đối với cả hai yếu tố dự đoán và tiêu chí. Chúng chỉ khác nhau ở chỗ các hàm trích xuất như residuals()hoặc fitted()sẽ đệm đầu ra của chúng với NAs cho các trường hợp bị bỏ qua với na.exclude, do đó có đầu ra có cùng độ dài với các biến đầu vào.

> 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) Vấn đề thực sự không nằm ở sự khác biệt này giữa na.omitna.exclude, dường như bạn không muốn xóa casewise mà đưa các biến tiêu chí vào tài khoản, cả hai đều làm.

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

Kết quả hồi quy phụ thuộc vào ma trận (giả của ma trận thiết kế , hệ số ) và chiếc mũ ma trận , giá trị được trang bị ). Nếu bạn không muốn xóa casewise, bạn cần một ma trận thiết kế khác nhau cho mỗi cột của , vì vậy không có cách nào phù hợp với hồi quy riêng cho từng tiêu chí. Bạn có thể cố gắng tránh chi phí bằng cách thực hiện một số thao tác sau: X β = X + Y H = X X + Y = H Y X YX+= =(X'X)-1X'Xβ^= =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

Lưu ý rằng có thể có nhiều cách tốt hơn để tính toán và , thay vào đó , bạn có thể kiểm tra phân tích . Cách tiếp cận SVD được giải thích ở đây trên SE . Tôi đã không tính thời gian cho cách tiếp cận trên với ma trận lớn chống lại việc sử dụng thực sự . H Q R YX+HQRYlm()


Điều đó có ý nghĩa dựa trên sự hiểu biết của tôi về cách na.exclude nên hoạt động. Tuy nhiên, nếu bạn gọi> X.both = cbind (X1, X2) và sau đó> dim (lm (X.both ~ Y, na.action = na.exclude) $ dư), bạn vẫn nhận được 94 phần dư, thay vì 97 và 97.
David Quigley

Đó là một sự cải tiến, nhưng nếu bạn nhìn vào phần dư (lm (X.both ~ Y, na.action = na.exclude)), bạn sẽ thấy rằng mỗi cột có sáu giá trị bị thiếu, mặc dù các giá trị bị thiếu trong cột 1 của X. cả hai đều từ các mẫu khác nhau so với các mẫu trong cột 2. Vì vậy, na.exclude đang bảo toàn hình dạng của ma trận dư, nhưng dưới mui xe R rõ ràng chỉ là hồi quy với các giá trị có trong tất cả các hàng của X.both. Có thể có một lý do thống kê tốt cho việc này, nhưng đối với ứng dụng của tôi thì đó là một vấn đề.
David Quigley

@David Tôi đã hiểu nhầm câu hỏi của bạn. Tôi nghĩ bây giờ tôi thấy quan điểm của bạn, và đã chỉnh sửa câu trả lời của tôi để giải quyết nó.
caracal

5

Tôi có thể nghĩ về hai cách. Một là kết hợp dữ liệu sử dụng na.excludevà sau đó tách dữ liệu lại:

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)

Một cách khác là sử dụng datađối số và tạo công thức.

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)

Nếu bạn đang thực hiện nhiều hồi quy, cách đầu tiên sẽ nhanh hơn, vì ít phép thuật nền được thực hiện. Mặc dù nếu bạn chỉ cần hệ số và số dư tôi đề nghị sử dụng lsfit, thì nó nhanh hơn nhiều lm. Cách thứ hai đẹp hơn một chút, nhưng trên máy tính xách tay của tôi đang cố gắng tóm tắt về hồi quy kết quả sẽ gây ra lỗi. Tôi sẽ cố gắng xem liệu đây có phải là một lỗi không.


Cảm ơn, nhưng lm (A.ex ~ B.ex) trong mã của bạn phù hợp với 9 điểm so với A1 (chính xác) và 9 điểm so với A2 (không mong muốn). Có 10 điểm đo cho cả B1 và ​​A2; Tôi đang đưa ra một điểm trong hồi quy của B1 so với A2 vì điểm tương ứng bị thiếu trong A1. Nếu đó chỉ là cách nó hoạt động tôi có thể chấp nhận điều đó, nhưng đó không phải là điều tôi đang cố gắng để R làm.
David Quigley

@David, oh, có vẻ như tôi đã hiểu nhầm vấn đề của bạn. Tôi sẽ đăng bản sửa lỗi sau.
mpiktas

1

Ví dụ sau đây cho thấy cách đưa ra dự đoán và phần dư phù hợp với khung dữ liệu gốc (sử dụng tùy chọn "na.action = na.exclude" trong lm () để chỉ định rằng NA nên được đặt trong các vectơ dư và dự đoán trong đó khung dữ liệu gốc có các giá trị bị thiếu. Nó cũng chỉ ra cách xác định liệu các dự đoán chỉ nên bao gồm các quan sát trong đó cả hai biến giải thích và biến phụ thuộc đã hoàn thành (nghĩa là các dự đoán trong mẫu) hoặc các quan sát trong đó các biến giải thích đã hoàn thành và do đó có thể dự đoán Xb, ( tức là, bao gồm dự đoán ngoài mẫu cho các quan sát có các biến giải thích hoàn chỉnh nhưng thiếu biến phụ thuộc).

Tôi sử dụng cbind để thêm các biến dự đoán và dư vào bộ dữ liệu ban đầu.

## 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)))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.