在R子集中没有使用subset()并使用[以更简洁的方式来防止打字错误?

Chr*_*ris 6 r

使用数据框时,通常需要一个子集.但是不鼓励使用子集函数.以下代码的问题是数据框名称重复两次.如果你复制并粘贴和munge代码,很容易不会意外地改变第二次提到的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
Run Code Online (Sandbox Code Playgroud)

有没有办法在不提及adf两次的情况下编写上述内容?不幸的是,使用with()或within(),我似乎无法访问整个adf?

子集(...)函数可以很容易,但他们警告不要使用它:

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

Chr*_*ris 1

经过一番思考,我写了一个超级简单的函数,名为给定:

given=function(.,...) { with(.,...) }
Run Code Online (Sandbox Code Playgroud)

这样,我就不必重复 data.frame 的名称。我还发现它比filter(). 见下文:

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)
Run Code Online (Sandbox Code Playgroud)

使用微基准

> 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
Run Code Online (Sandbox Code Playgroud)

我注意到given() 实际上比 快一点with(),因为变量名的长度。

,的巧妙之处在于given,您可以在不进行赋值的情况下内联执行一些操作:给定(data.frame(a=1:10,b=11:20),.[a>5 & b<18,])