data.table 中的 dplyr::slice [重复]
Posted
技术标签:
【中文标题】data.table 中的 dplyr::slice [重复]【英文标题】:dplyr::slice in data.table [duplicate] 【发布时间】:2018-10-10 03:49:55 【问题描述】:在data.table
中执行以下操作的惯用方式是什么?
library(dplyr)
df %>%
group_by(b) %>%
slice(1:10)
我可以的
library(data.table)
df[, .SD[1:10]
, by = b]
但这看起来要慢得多。有没有更好的办法?
set.seed(0)
df <- rep(1:500, sample(500:1000, 500, T)) %>%
data.table(a = runif(length(.))
,b = .)
f1 <- function(df)
df %>%
group_by(b) %>%
slice(1:10)
f2 <- function(df)
df[, .SD[1:10]
, by = b]
library(microbenchmark)
microbenchmark(f1(df), f2(df))
#Unit: milliseconds
# expr min lq mean median uq max neval
# f1(df) 17.67435 19.50381 22.06026 20.50166 21.42668 78.3318 100
# f2(df) 69.69554 79.43387 119.67845 88.25585 106.38661 581.3067 100
========== 推荐方法的基准 ==========
set.seed(0)
df <- rep(1:500, sample(500:1000, 500, T)) %>%
data.table(a = runif(length(.))
,b = .)
use.slice <- function(df)
df %>%
group_by(b) %>%
slice(1:10)
IndexSD <- function(df)
df[, .SD[1:10]
, by = b]
Index.I <- function(df)
df[df[, .I[seq_len(10)], by = b]$V1]
use.head <- function(df)
df[, head(.SD, 10)
, by = b]
library(microbenchmark)
microbenchmark(use.slice(df)
, IndexSD(df)
, Index.I(df)
, use.head(df)
, unit = "relative"
, times = 100L)
#Unit: relative
# expr min lq mean median uq max neval
# use.slice(df) 9.804549 10.269234 9.167413 8.900060 8.782862 6.520270 100
# IndexSD(df) 38.881793 42.548555 39.044095 38.636523 39.942621 18.981748 100
# Index.I(df) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 100
# use.head(df) 3.666898 4.033038 3.728299 3.408249 3.545258 3.951565 100
【问题讨论】:
head(.SD, 10)
也应该很快。
谢谢@Frank。我在测试用例中添加了 4 种方法的基准。
【参考方案1】:
我们可以使用.I
提取行索引,应该更快
out <- df[df[, .I[seq_len(10)], by = b]$V1]
dim(out)
#[1] 5000 2
检查是否有 NA(正如 OP 评论的那样)
any(out[, Reduce(`|`, lapply(.SD, is.na))])
#[1] FALSE
dim(df)
#[1] 374337 2
基准测试
f3 <- function(df)
df[df[, .I[seq_len(10)], by = b]$V1]
microbenchmark(f1(df), f2(df), f3(df), unit = "relative", times = 10L)
#Unit: relative
# expr min lq mean median uq max neval cld
# f1(df) 5.727822 5.480741 4.945486 5.672206 4.317531 5.10003 10 b
# f2(df) 24.572633 23.774534 17.842622 23.070634 16.099822 11.58287 10 c
# f3(df) 1.000000 1.000000 1.000000 1.000000 1.000000 1.00000 10 a
【讨论】:
@Renu 我不明白。df[df[, .I[seq_len(10)], by = b]$V1] %>% dim# [1] 5000 2# dim(df)# [1] 374337
2
不确定那里发生了什么。清除了我的会话,您的解决方案按预期工作。
@Renu 抱歉,我没有收到评论。内部df[, .I[seq_len(10)], by = b]
返回列“V1”,即列索引。我们使用$V1
提取它并使用它来对数据进行子集化。版本可能有问题。当我做其他事情时,我也注意到了这些问题。为了使其更安全,您可以分两步执行此操作 `i1
@akrun 你知道为什么 indexSD 和 use.head(OP 创建的函数)只有在只有一组时才有效吗?下面的代码给了我Empty data.table (0 rows and 2 cols): samples,groups
:samples<-c("A","A","A","A","B","B","B","C","C","C")
groups<-c(1,1,2,3,1,1,1,2,2,2)
df<- data.frame(samples,groups)
library(data.table)
setDT(df)
df[, .SD[1:2], by = .(samples, groups)]
以上是关于data.table 中的 dplyr::slice [重复]的主要内容,如果未能解决你的问题,请参考以下文章
检查一个 data.table 列中的所有元素以查看另一个 data.table 列中出现的每个值的最快方法