我有一个公式和一个数据帧,我想提取model.matrix()
。但是,我需要得到的矩阵包含在原始数据集中发现的NAs。如果我用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
Joris的建议是有效的,但是更快捷、更简洁的方法是通过全局名称。动作设置。"Pass"选项实现了我们从原始数据集中保留NA的目标。
选项1:Pass
结果矩阵将包含与原始数据集对应的行中的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后将其更改回来。
另一种方法是使用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
时保持。
在看了mattdevlin和Nathan Gould的答案后,我偶然发现了一个更简单的解决方案:
model.matrix.lm(ff, dat, na.action = "na.pass")
model.matrix.default
可能不支持na.action
参数,但model.matrix.lm
支持!
(我发现model.matrix.lm
从Rstudio的自动完成建议—如果您没有加载任何添加其他库,它似乎是model.matrix
的唯一非默认方法。然后我猜它可能支持na.action
参数。)
您可以根据行名对model.matrix
对象进行一些改动:
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
在任何情况下,这两种方法都可以合并到一个可以处理更复杂公式的函数中。我把练习留给读者(当我在论文中遇到这样的句子时,我会讨厌它;-))