R จัดการค่าที่ขาดหายไปใน lm ได้อย่างไร


32

ฉันต้องการถดถอยเวกเตอร์ B เทียบกับแต่ละคอลัมน์ในเมทริกซ์ A นี่เป็นเรื่องไม่สำคัญหากไม่มีข้อมูลที่หายไป แต่ถ้าเมทริกซ์ 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 กับคอลัมน์ใน A ทีละรายการ" ซึ่งหมายถึงการโทรครั้งละครั้งเป็น lm แก้ไขเพื่อสะท้อนสิ่งนี้
David Quigley

1
การเรียกครั้งต่อครั้งไปที่ lm / regression ไม่ใช่วิธีที่ดีในการดำเนินการถดถอย (ไปตามคำจำกัดความของการถดถอยซึ่งเป็นการค้นหาผลกระทบบางส่วนของตัวทำนายแต่ละตัวบนการตอบสนอง / ผลลัพธ์ที่ได้จากสถานะของคนอื่น ๆ ตัวแปร)
KarthikS

คำตอบ:


23

แก้ไข: ฉันเข้าใจผิดคำถามของคุณ มีสองด้าน:

ก) na.omitและna.excludeทั้งสองทำการลบอย่างน่าพิศวงด้วยความเคารพต่อทั้งตัวทำนายและเกณฑ์ พวกเขาแตกต่างกันในฟังก์ชั่นการแยกเช่นresiduals()หรือfitted()จะ pad เอาท์พุทของพวกเขากับ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คุณไม่ต้องการให้มีการลบแบบ casewise ที่คำนึงถึงตัวแปรเงื่อนไขซึ่งทั้งสองทำ

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

ผลลัพธ์การถดถอยจะขึ้นอยู่กับเมทริกซ์ (pseudoinverse ของเมทริกซ์การออกแบบ , สัมประสิทธิ์ ) และหมวก เมทริกซ์ , ค่าติดตั้ง ) หากคุณไม่ต้องการการลบแบบ Casewise คุณต้องมีเมทริกซ์การออกแบบแตกต่างกันสำหรับแต่ละคอลัมน์ของดังนั้นจึงไม่มีวิธีแก้ไขการถดถอยแบบแยกต่างหากสำหรับแต่ละเกณฑ์ คุณสามารถพยายามหลีกเลี่ยงค่าใช้จ่ายโดยทำบางสิ่งตามบรรทัดต่อไปนี้: 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

โปรดทราบว่าอาจมีวิธีที่ดีกว่าตัวเลขในการคำนวณและคุณสามารถตรวจสอบ -decomposition แทน SVD-วิธีการจะมีการอธิบายที่นี่ใน SE ฉันไม่ได้หมดเวลาวิธีการข้างต้นด้วยการฝึกอบรมใหญ่กับการใช้จริง H Q R YX+HQRYlm()


นั่นทำให้รู้สึกถึงความเข้าใจของฉันเกี่ยวกับวิธี na.exclude ควรทำงาน อย่างไรก็ตามถ้าคุณโทร> X.both = cbind (X1, X2) และจากนั้น> สลัว (lm (X.both ~ Y, na.action = na.exclude) $ ที่เหลือ) คุณยังคงได้รับ 94 ที่เหลือแทน 97 และ 97.
David Quigley

นั่นเป็นการปรับปรุง แต่ถ้าคุณดูที่เหลือ (lm (X.both ~ Y, na.action = na.exclude)) คุณจะเห็นว่าแต่ละคอลัมน์มีค่าที่หายไปหกค่าแม้ว่าค่าที่หายไปในคอลัมน์ 1 ของ X ทั้งสองมาจากตัวอย่างที่แตกต่างจากที่อยู่ในคอลัมน์ 2 ดังนั้น na.exclude จึงรักษารูปร่างของเมทริกซ์ที่เหลืออยู่ แต่ภายใต้ประทุนฮูด R ดูเหมือนว่าจะถดถอยเฉพาะกับค่าที่มีอยู่ในทุกแถวของ X.both อาจมีเหตุผลทางสถิติที่ดีสำหรับเรื่องนี้ แต่สำหรับใบสมัครของฉันมันเป็นปัญหา
David Quigley

@ David ฉันเข้าใจผิดคำถามของคุณ ฉันคิดว่าฉันเห็นจุดของคุณแล้วและได้แก้ไขคำตอบของฉันเพื่อแก้ไข
caracal

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 Quigley

@ David, โอ้ดูเหมือนว่าฉันเข้าใจผิดปัญหาของคุณ ฉันจะโพสต์การแก้ไขในภายหลัง
mpiktas

1

ตัวอย่างต่อไปนี้แสดงวิธีการคาดคะเนและการตกค้างที่สอดคล้องกับ dataframe ดั้งเดิม (โดยใช้ตัวเลือก "na.action = na.exclude" ใน lm () เพื่อระบุว่าควรวาง NA ไว้ในเวกเตอร์ที่เหลือและการทำนายที่ซึ่ง dataframe ดั้งเดิม มีค่าที่ขาดหายไปนอกจากนี้ยังแสดงวิธีการระบุว่าการคาดการณ์ควรรวมเฉพาะการสังเกตที่ทั้งอธิบายและตัวแปรที่สมบูรณ์ (เช่นการคาดการณ์ในตัวอย่างอย่างเคร่งครัด) หรือการสังเกตที่ตัวแปรอธิบายเสร็จสมบูรณ์และการทำนาย 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)))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.