当我需要过滤一个data.frame,即提取满足特定条件的行时,我更喜欢使用subset
函数:
subset(airquality, Month == 8 & Temp > 90)
而不是 [
函数:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
我偏爱的主要原因有两个:
我发现代码从左到右读起来更好。即使对 R 一无所知的人也可以知道上面的子集语句在做什么。因为列可以在选择表达式中被称为变量,所以我可以节省一些击键。在我上面的例子中,我只需要用子集输入一次空气质量,但用 [.
所以我过着幸福的生活,到处使用 subset
,因为它更短且可读性更好,甚至向我的 R 程序员同事宣传它的美感。但是昨天我的世界分崩离析。在阅读 subset
文档时,我注意到这一部分:
警告 这是一个旨在以交互方式使用的便利功能。对于编程,最好使用像 [ 之类的标准子集函数,特别是参数子集的非标准评估可能会产生意想不到的后果。
有人可以帮助澄清作者的意思吗?
首先,“交互使用”是什么意思?我知道什么是交互式会话,而不是在 BATCH 模式下运行的脚本,但我看不出它应该有什么不同。
那么,您能否解释一下“参数子集的非标准评估”以及为什么它很危险,也许可以提供一个例子?
with(airquality, airquality[Month == 8 & Temp > 90, ])
一起使用略少(但比子集少)
dplyr::filter
也有同样的问题。即,如果环境碰巧有一个具有该名称的变量,它将使用它而不是数据框中的变量。使调试混乱!
@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)
(运行它们,自己看看,这太疯狂了。)
[
也更快:
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
subset
与 [
不同,删除过滤器评估为 NA
的行。这样做,您会发现它们在“相当”比较时都一样快:x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })
不定期副业成功案例分享
subset(mtcars, cyl == 4)
(在顶层)时,R 在哪里寻找 cyl?如果它查看传递给subset()
的mtcars
对象,那么即使scramble
在另一个函数中,它是否应该能够找到cyl
,因为mtcars
仍在传递给它?如果我的问题没有意义,您可以详细说明为什么 R 无法再找到cyl
。谢谢!subset.data.frame
,我们当时试图评估的只是condition
。这在mtcars
中不存在。因此subset.data.frame
使用enclos = parent.frame()
来确保condition
被正确评估为cyl == 4
。但是后来我们又回到了封闭的框架,现在当 R 寻找cyl
时,它不再寻找mtcars
的内部。如果我们不使用enclos
,那么subset(mtcars,cyl == a)
之类的东西就根本不起作用。subset.data.frame
的最后一行是x[r, vars, drop = drop]
。问题是如何从未引用的subset
和select
参数中获取可以有效传递给[.data.frame
的内容。[
和subset()
之间的重要区别在于该函数...[
将其替换为子集,这会产生与使用subset
的代码相同的“奇怪”结果 - 至少在这里:/ 也清理 R 3.4.3