在 R 子集设置中不使用子集()并以更简洁的方式使用 [ 来防止拼写错误?
Posted
技术标签:
【中文标题】在 R 子集设置中不使用子集()并以更简洁的方式使用 [ 来防止拼写错误?【英文标题】:In R subsetting without using subset() and use [ in a more concise manner to prevent typos? 【发布时间】:2015-07-12 23:55:30 【问题描述】:在处理数据帧时,通常需要一个子集。但是不鼓励使用子集函数。以下代码的问题是数据框名称重复了两次。如果你复制粘贴代码,很容易不小心不更改第二次提及的 adf,这可能是一场灾难。
adf=data.frame(a=1:10,b=11:20)
print(adf[which(adf$a>5),]) ##alas, adf mentioned twice
print(with(adf,adf[a>5,])) ##alas, adf mentioned twice
print(subset(adf,a>5)) ##alas, not supposed to use subset
有没有办法在不提及 adf 两次的情况下编写上述内容?不幸的是,使用 with() 或 inside(),我似乎无法访问整个 adf?
subset(...) 函数可以让它变得简单,但他们警告不要使用它:
这是一个旨在交互使用的便利功能。对于编程,最好使用像 [ 这样的标准子集函数,特别是参数子集的非标准评估可能会产生意想不到的后果。
【问题讨论】:
使用来自dplyr
的filter
。即filter(adf, a >5)
类似于subset
。如果您使用的是data.table
。 setDT(adf)[a>5]
我和@akrun 在一起,很久以前就停止使用data.frames
。一旦您将数据集转换为data.table
,您的所有语法都会变得更短。尽管我只想提一下,您在这里使用了太多代码。您既不需要print
或which
,也不需要adf[adf$a>5,]
,这反过来又不会让我感到困惑。
如果你想知道为什么不鼓励使用subset()
,请看看this SO question。
两次写入数据集的名称应该是您最不担心的问题。你不应该复制/粘贴任何东西
akrun,我喜欢你对过滤器的建议。
【参考方案1】:
正如@akrun 所说,我会使用dplyr
的filter
函数:
require("dplyr")
new <- filter(adf, a > 5)
new
在实践中,我发现子集符号 ([ ]
) 没有问题,因为如果我复制代码块,我会在 RStudio 中使用查找和替换来替换所选代码中对数据框的所有提及。相反,我使用 dplyr 是因为新用户(和我自己!)更容易理解符号和语法,并且因为 dplyr 功能“做好一件事”。
【讨论】:
【参考方案2】:经过一番思考,我写了一个超级简单的函数,叫做 given:
given=function(.,...) with(.,...)
这样我就不用重复data.frame的名字了。我还发现它比 filter()
快 14 倍。见下文:
adf=data.frame(a=1:10,b=11:20)
given=function(.,...) with(.,...)
with(adf,adf[a>5 & b<18,]) ##adf mentioned twice :(
given(adf,.[a>5 & b<18,]) ##adf mentioned once :)
dplyr::filter(adf,a>5,b<18) ##adf mentioned once...
microbenchmark(with(adf,adf[a>5 & b<18,]),times=1000)
microbenchmark(given(adf,.[a>5 & b<18,]),times=1000)
microbenchmark(dplyr::filter(adf,a>5,b<18),times=1000)
使用微基准测试
> adf=data.frame(a=1:10,b=11:20)
> given=function(.,...) with(.,...)
> with(adf,adf[a>5 & b<18,]) ##adf mentioned twice :(
a b
6 6 16
7 7 17
> given(adf,.[a>5 & b<18,]) ##adf mentioned once :)
a b
6 6 16
7 7 17
> dplyr::filter(adf,a>5,b<18) ##adf mentioned once...
a b
1 6 16
2 7 17
> microbenchmark(with(adf,adf[a>5 & b<18,]),times=1000)
Unit: microseconds
expr min lq mean median uq max neval
with(adf, adf[a > 5 & b < 18, ]) 47.897 60.441 67.59776 67.284 70.705 361.507 1000
> microbenchmark(given(adf,.[a>5 & b<18,]),times=1000)
Unit: microseconds
expr min lq mean median uq max neval
given(adf, .[a > 5 & b < 18, ]) 48.277 50.558 54.26993 51.698 56.64 272.556 1000
> microbenchmark(dplyr::filter(adf,a>5,b<18),times=1000)
Unit: microseconds
expr min lq mean median uq max neval
dplyr::filter(adf, a > 5, b < 18) 524.965 581.2245 748.1818 674.7375 889.7025 7341.521 1000
我注意到 given(
) 实际上比 with()
快一点,因为变量名的长度。
given
的巧妙之处在于,您可以在没有赋值的情况下内联执行一些操作:
给定(data.frame(a=1:10,b=11:20),.[a>5 & b
【讨论】:
以上是关于在 R 子集设置中不使用子集()并以更简洁的方式使用 [ 来防止拼写错误?的主要内容,如果未能解决你的问题,请参考以下文章