在R中,对数据框的行进行子集操作的更快方法是什么?

17

我一直在使用这两种方法交替地从R数据框中对数据进行子集筛选。
方法1
subset_df <- df[which(df$age>5) , ]
方法2
subset_df <- subset(df, age>5)

我有两个问题关于这些。
1. 如果我有非常大的数据,哪一个更快?
2. 这篇文章Subsetting data frames in R表明上述两种方法之间实际上是有差异的。其中一种可以准确地处理NA(缺失值)。那么哪种方法更安全可靠呢?


尝试使用 microbenchmark 包运行一些基准测试。 - nrussell
4
如果你担心在大型数据集上的速度问题,你应该考虑使用 dplyrdata.table(或者将 dplyr 作为 data.table 的前端)来代替。 - Ben Bolker
请参考以下网址:https://dev59.com/52kw5IYBdhLWcg3wfKhB - talat
1
使用 [ 是编程中的安全选择,而 subset 仅适用于交互式使用的便利函数。有关更多信息,请参见上面的链接。 - talat
2个回答

28

这个问题要求更快地子集行数据框。最快的方法是使用data.table。

set.seed(1)  # for reproducible example
# 1 million rows - big enough?
df <- data.frame(age=sample(1:65,1e6,replace=TRUE),x=rnorm(1e6),y=rpois(1e6,25))

library(microbenchmark)
microbenchmark(result<-df[which(df$age>5),],
               result<-subset(df, age>5), 
               result<-df[df$age>5,],
               times=10)
# Unit: milliseconds
#                               expr       min        lq    median       uq      max neval
#  result <- df[which(df$age > 5), ]  77.01055  80.62678  81.43786 133.7753 145.4756    10
#      result <- subset(df, age > 5) 190.89829 193.04221 197.49973 203.7571 263.7738    10
#         result <- df[df$age > 5, ] 169.85649 171.02084 176.47480 185.9394 191.2803    10

library(data.table)
DT <- as.data.table(df)     # data.table
microbenchmark(DT[age > 5],times=10)
# Unit: milliseconds
#         expr      min       lq  median       uq      max neval
#  DT[age > 5] 29.49726 29.93907 30.1813 30.67168 32.81204    10

因此在这个简单的案例中,data.table比which(...)快两倍以上,并且比subset(...)快六倍以上。


注意:在Windows上运行R 3.3.1 64位版本时,前三个选项之间的差异很小(平均值为110-114,中位数为77-87)。也许R处理子集的方式已经被优化了?我还没有尝试过data.table,我认为它仍然更快。 - Rob Hall

5

我通过以下方式重写了代码:

  • 使用子集运算符[[

  • 使用"dplyr"包中的filter函数;

  • 编写了一个利用标准评估的函数。

最佳结果是使用 data.tabledf %>% filter(age > 5) 运算符。因此,带有 dplyr 的 data.frame 也可能有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接