在 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(...) 函数可以让它变得简单,但他们警告不要使用它:

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

【问题讨论】:

使用来自dplyrfilter。即filter(adf, a >5) 类似于subset。如果您使用的是data.tablesetDT(adf)[a>5] 我和@akrun 在一起,很久以前就停止使用data.frames。一旦您将数据集转换为data.table,您的所有语法都会变得更短。尽管我只想提一下,您在这里使用了太多代码。您既不需要printwhich,也不需要adf[adf$a>5,] ,这反过来又不会让我感到困惑。 如果你想知道为什么不鼓励使用subset(),请看看this SO question。 两次写入数据集的名称应该是您最不担心的问题。你不应该复制/粘贴任何东西 akrun,我喜欢你对过滤器的建议。 【参考方案1】:

正如@akrun 所说,我会使用dplyrfilter 函数:

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 子集设置中不使用子集()并以更简洁的方式使用 [ 来防止拼写错误?的主要内容,如果未能解决你的问题,请参考以下文章

R:基于多个条件的两个数据帧的子集

R中按日期范围设置的子集data.table

根据 R 中的文件名读取栅格子集

R语言入门——取子集

R语言入门——取子集

R语言入门——取子集