为什么'['比'子集'好?

当我需要过滤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模式下运行的脚本,但我不知道它应该有什么不同。

那么,你能不能解释一下“参数子集的非标准求值"为什么它是危险的,也许可以举个例子?

106051 次浏览

这个问题在@James的评论中得到了很好的回答,他指出Hadley Wickham对subset(以及类似的功能)(在这里)的危险做了很好的解释。去读吧!

这本书读起来有点长,所以在这里记录哈德利使用的最直接解决“会出什么问题”的例子可能会有所帮助。:

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)

(自己运行看看,这很疯狂。)

而且[更快:

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