首页 文章

为什么`[`比`子集更好?

提问于
浏览
371

当我需要过滤data.frame,即提取满足特定条件的行时,我更喜欢使用 subset 函数:

subset(airquality, Month == 8 & Temp > 90)

而不是 [ 函数:

airquality[airquality$Month == 8 & airquality$Temp > 90, ]

我偏好有两个主要原因:

  • 我发现代码从左到右读起来更好 . 即使对R一无所知的人也可以说出上面的声明在做什么 .

  • 因为列可以在 select 表达式中称为变量,所以我可以保存几个键击 . 在上面的例子中,我只需要用 subset 键入 airquality 一次,而使用 [ 键入三次 .

所以我生活得很幸福,到处都是 subset 因为它更短,读起来更好,甚至为我的R编码员提倡它的美丽 . 但昨天我的世界崩溃了 . 在阅读 subset 文档时,我注意到这一部分:

警告这是一个便于交互使用的便利功能 . 对于编程,最好使用[等标准子集函数,特别是参数子集的非标准评估可能会产生意想不到的后果 .

有人可以帮助澄清作者的意思吗?

首先,他们的意思是“交互使用”?我知道什么是交互式会话,而不是在BATCH模式下运行的脚本,但我不知道它应该有什么区别 .

那么,请你解释一下“论证子集的非标准评估”以及为什么它是危险的,或许可以提供一个例子?

2 回答

  • 221

    这个问题在@James的评论中得到了很好的回答,指出了Hadley Wickham对 subset (以及类似函数)[here]的危险性的一个很好的解释 . 去读吧!

    这是一个有点长的阅读,所以在这里记录Hadley使用的最直接解决“什么可能出错?”的问题可能会有所帮助:

    Hadley建议使用以下示例:假设我们要使用以下函数对数据框进行子集化,然后重新排序:

    scramble <- function(x) x[sample(nrow(x)), ]
    
    subscramble <- function(x, condition) {
      scramble(subset(x, condition))
    }
    
    subscramble(mtcars, cyl == 4)
    

    这会返回错误:

    eval(expr,envir,enclos)中的错误:找不到对象'cyl'

    因为R不再“知道”在哪里找到名为'cyl'的对象 . 他还指出,如果在全球环境中有一个名为'cyl'的对象,可能会发生真正奇怪的事情:

    cyl <- 4
    subscramble(mtcars, cyl == 4)
    
    cyl <- sample(10, 100, rep = T)
    subscramble(mtcars, cyl == 4)
    

    (运行它们并亲眼看看,它非常疯狂 . )

  • 25

    [ 也更快:

    require(microbenchmark)        
    microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,])
        Unit: microseconds
                                                               expr     min       lq   median       uq     max neval
                         subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903   100
         airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058   100
    

相关问题