提问



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


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


而不是[函数:


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


我偏好有两个主要原因:



  1. 我发现代码从左到右读得更好。甚至那些对R一无所知的人也可以说出上面的subset陈述是做什么的。

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



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



  警告

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



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


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


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

最佳参考


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


这是一个有点长的阅读,所以在这里记录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)


(运行它们,亲眼看看,它真的很疯狂。)

其它参考1


[也更快:


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