【问题标题】:model.matrix() with na.action=NULL?model.matrix() with na.action=NULL?
【发布时间】:2011-08-02 17:44:39
【问题描述】:

我有一个公式和一个数据框,我想提取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

【问题讨论】:

    标签: r matrix na


    【解决方案1】:

    您可以根据行名对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
    

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

    【讨论】:

    • “我把练习留给读者”——但它非常适合做课堂笔记;)
    • match 通话很棒,这就是我所缺少的!
    • match() 效果很好。顺便说一句,这解决了我一直在努力解决的另一个问题。非常感谢!
    【解决方案2】:

    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 &lt;- options('na.action') 之类的东西,然后在制作 model.matrix 后将其更改回来。

    【讨论】:

    • 每天学习新东西。
    • 明确地说,将options('na.action') 重置为其原始状态的一种方法是:current.na.action &lt;- options('na.action',然后是options('na.action' = current.na.action$na.action)。请注意,不使用名称 'na.action' 从 current.na.action 中提取字符串变量可能会导致无限递归和“保护堆栈溢出”错误,尤其是当您在带有 on.exit 的函数中使用该构造时。跨度>
    【解决方案3】:

    另一种方法是使用带有参数na.action=na.passmodel.frame 函数作为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 被调用时维护。

    【讨论】:

    • 谢谢,但我问题的第一段解释了为什么这在我想到的应用程序中不起作用。
    • @Vincent,model.frame 只是model.matrix 的一个参数,所以输出格式为model.matrix。我展示的输出不是你想要的吗?
    • 哇!我真的需要提高我的阅读能力。这是一个非常酷的解决方案;不知道你能做到。谢谢!
    • 这个答案似乎是要走的路;希望人们能找到它,即使旧答案的评分更高
    【解决方案4】:

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

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

    model.matrix.default 可能不支持 na.action 参数,但 model.matrix.lm 支持!

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

    【讨论】:

    • 谢谢@onestop,我认为这应该是推荐的答案。
    • 这应该是推荐的答案!
    • 这个效果最好。 model.matrix 似乎不尊重 na.action。
    猜你喜欢
    • 2019-09-07
    • 2022-01-17
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    • 2017-04-16
    • 2014-07-30
    相关资源
    最近更新 更多