44

我有一个公式和一个数据框,我想提取model.matrix(). 但是,我需要生成的矩阵包含在原始数据集中找到的 NA。如果我model.frame()用来做这个,我会简单地通过它na.action=NULL。但是,我需要的输出是model.matrix()格式。具体来说,我只需要右侧变量,我需要输出是一个矩阵(而不是数据框),我需要将因子转换为一系列虚拟变量。

我确信我可以使用循环或其他东西来破解某些东西,但我想知道是否有人可以提出更清洁、更有效的解决方法。非常感谢您的时间!

这是一个例子:

dat <- data.frame(matrix(rnorm(20),5,4), gl(5,2))
dat[3,5] <- NA
names(dat) <- c(letters[1:4], 'fact')
ff <- a ~ b + fact

# This omits the row with a missing observation on the factor
model.matrix(ff, dat) 

# This keeps the NA, but it gives me a data frame and does not dichotomize the factor
model.frame(ff, dat, na.action=NULL) 

这是我想要获得的:

   (Intercept)          b fact2 fact3 fact4 fact5
1            1  0.7266086     0     0     0     0
2            1 -0.6088697     0     0     0     0
3            NA 0.4643360     NA    NA    NA    NA
4            1 -1.1666248     1     0     0     0
5            1 -0.7577394     0     1     0     0
6            1  0.7266086     0     1     0     0
7            1 -0.6088697     0     0     1     0
8            1  0.4643360     0     0     1     0
9            1 -1.1666248     0     0     0     1
10           1 -0.7577394     0     0     0     1
4

4 回答 4

53

Joris 的建议有效,但更快速、更简洁的方法是通过全局 na.action 设置。“通过”选项实现了我们从原始数据集中保留 NA 的目标。

选项 1:通过

结果矩阵将包含与原始数据集对应的行中的 NA。

options(na.action='na.pass')
model.matrix(ff, dat) 

选项 2:省略

生成的矩阵将跳过包含 NA 的行。

options(na.action='na.omit')
model.matrix(ff, dat) 

选项 3:失败

如果原始数据包含 NA,则会发生错误。

options(na.action='na.fail')
model.matrix(ff, dat) 

当然,更改全局选项时要小心,因为它们会改变代码其他部分的行为。谨慎的人可能会用类似的东西存储原始设置current.na.action <- options('na.action'),然后在制作 model.matrix 后将其更改回来。

于 2013-10-23T14:30:00.220 回答
38

另一种方法是使用model.frame带参数的函数na.action=na.pass作为第二个参数model.matrix

> model.matrix(ff, model.frame(~ ., dat, na.action=na.pass))
   (Intercept)          b fact2 fact3 fact4 fact5
1            1 -1.3560754     0     0     0     0
2            1  2.5476965     0     0     0     0
3            1  0.4635628    NA    NA    NA    NA
4            1 -0.2871379     1     0     0     0
5            1  2.2684958     0     1     0     0
6            1 -1.3560754     0     1     0     0
7            1  2.5476965     0     0     1     0
8            1  0.4635628     0     0     1     0
9            1 -0.2871379     0     0     0     1
10           1  2.2684958     0     0     0     1

model.frame允许您设置适当的操作,当被调用na.action时维护该操作。model.matrix

于 2015-08-11T19:04:33.520 回答
20

在查看了mattdevlinNathan Gould的答案后,我偶然发现了一个更简单的解决方案:

 model.matrix.lm(ff, dat, na.action = "na.pass")

model.matrix.default可能不支持这个na.action论点,但是支持model.matrix.lm

(我从 Rstudio 的自动完成建议中找到——如果你没有加载任何添加其他库的库,model.matrix.lm它似乎是唯一的非默认方法。然后我猜它可能支持这个论点。)model.matrixna.action

于 2018-03-02T14:43:00.603 回答
16

您可以model.matrix根据 rownames 对对象进行一些处理:

MM <- model.matrix(ff,dat)
MM <- MM[match(rownames(dat),rownames(MM)),]
MM[,"b"] <- dat$b
rownames(MM) <- rownames(dat)

这使 :

> MM
     (Intercept)         b fact2 fact3 fact4 fact5
1              1 0.9583010     0     0     0     0
2              1 0.3266986     0     0     0     0
3             NA 1.4992358    NA    NA    NA    NA
4              1 1.2867461     1     0     0     0
5              1 0.5024700     0     1     0     0
6              1 0.9583010     0     1     0     0
7              1 0.3266986     0     0     1     0
8              1 1.4992358     0     0     1     0
9              1 1.2867461     0     0     0     1
10             1 0.5024700     0     0     0     1

或者,您可以使用contrasts()来为您完成工作。手动构造矩阵将是:

cont <- contrasts(dat$fact)[as.numeric(dat$fact),]
colnames(cont) <- paste("fact",colnames(cont),sep="")
out <- cbind(1,dat$b,cont)
out[is.na(dat$fact),1] <- NA
colnames(out)[1:2]<- c("Intercept","b")
rownames(out) <- rownames(dat)

这使 :

> out
     Intercept          b fact2 fact3 fact4 fact5
1            1  0.2534288     0     0     0     0
2            1  0.2697760     0     0     0     0
3           NA -0.8236879    NA    NA    NA    NA
4            1 -0.6053445     1     0     0     0
5            1  0.4608907     0     1     0     0
6            1  0.2534288     0     1     0     0
7            1  0.2697760     0     0     1     0
8            1 -0.8236879     0     0     1     0
9            1 -0.6053445     0     0     0     1
10           1  0.4608907     0     0     0     1

在任何情况下,这两种方法都可以合并到一个可以处理更复杂公式的函数中。我把练习留给读者(当我在论文中遇到这句话时,我讨厌什么;-))

于 2011-04-11T08:20:01.720 回答