我有一个问题,我需要根据一个列选择并保存一部分表的一部分,然后从源表中消除匹配保存表的列中值的源表的行。
我发现dplyr和data。表比基本r慢,想知道我在这里做错了什么(我不知道吗?(,或者如果有人知道更快的解决方案这。
我需要在搜索df和〜10K迭代中缩放〜1000万行。
这是一个合理的可重复示例...
(编辑:我意识到我正在做的事情可以通过组过滤器来实现。留下更新的可复制示例,并在下面的注释和我的更新解决方案中进行一些调整。-请注意,原始内容不包括bind_cols(y_list(详细信息。回想起来,我应该在此示例中包括在内。(
library(dplyr)
library(data.table)
library(microbenchmark)
microbenchmark(base = {
for(y_check in y_unique) {
y_list[[as.character(y_check)]] <- df[df$y == y_check, ]
df <- df[!df$x %in% y_list[[as.character(y_check)]]$x, ]
}
out <- bind_rows(y_list)
}, dplyr = {
for(y_check in y_unique) {
y_list[[as.character(y_check)]] <- filter(df, y == y_check)
df <- df[!df$x %in% y_list[[as.character(y_check)]]$x, ]
}
out <- bind_rows(y_list)
}, data.table = {
for(y_check in y_unique) {
y_list[[as.character(y_check)]] <- dt[y == y_check]
dt <- dt[!x %in% y_list[[as.character(y_check)]]$x]
}
out <- do.call(rbind, y_list)
}, alternate = {
df <- group_by(df, x)
out <- filter(df, y == min(y))
}, times = 10, setup = {
set.seed(1)
df <- data.frame(x = sample(1:1000, size = 1000, replace = TRUE),
y = sample(1:100, size = 1000, replace = TRUE))
dt <- data.table(df)
y_unique <- sort(unique(df$y))
y_list <- setNames(rep(list(list()), length(y_unique)), y_unique)
})
我得到:
Unit: milliseconds
expr min lq mean median uq max neval
base 12.939135 13.22883 13.623098 13.500897 13.95468 14.517167 10
dplyr 41.517351 42.22595 50.041123 45.199978 61.33194 65.927611 10
data.table 228.014360 233.98309 248.281965 240.172383 263.39943 287.706941 10
alternate 3.310031 3.42016 3.745013 3.454537 4.17488 4.497455 10
在我的真实数据上,我或多或少地获得了相同的数据。基数比dplyr快2倍以上。表速度很慢。有什么想法吗?
使用JOIN(大约13s(的一些选项(与实际尺寸的任何联接方法约13s(:
DT <- copy(dt)
setorder(DT, y, x)
DT[DT[.(unique(x)), on=.(x), .(y=first(y)), by=.EACHI], on=.(x,y)]
或原始订购很重要:
DT2 <- copy(dt)
setorder(DT2[, rn := .I], y, x)
dt[sort(DT2[.(unique(x)), on=.(x), rn[y==first(y)], by=.EACHI]$V1)]
,还使用OP中提到的min
:
DT0[, rn := .I]
dt[DT0[.(unique(x)), on=.(x), rn[y==min(y)], by=.EACHI][order(V1), V1]]
计时代码:
base <- function() {
for(y_check in y_unique) {
y_list[[as.character(y_check)]] <- df[df$y == y_check, ]
df <- df[!df$x %in% y_list[[as.character(y_check)]]$x, ]
}
do.call(rbind, y_list)
} #base
mtd0 <- function() {
for(y_check in y_unique) {
y_list[[as.character(y_check)]] <- dt[y == y_check]
dt <- dt[!x %in% y_list[[as.character(y_check)]]$x]
}
out <- rbindlist(y_list)
} #mtd0
join_mtd <- function() {
setorder(DT, y, x)
dt[DT[.(unique(x)), on=.(x), .(y=first(y)), by=.EACHI], on=.(x,y)]
} #join_mtd
join_mtd2 <- function() {
setorder(DT2[, rn := .I], y, x)
dt[sort(DT2[.(unique(x)), on=.(x), rn[y==first(y)], by=.EACHI]$V1)]
} #join_mtd2
join_mtd3 <- function() {
DT0[, rn := .I]
dt[DT0[.(unique(x)), on=.(x), rn[y==min(y)], by=.EACHI][order(V1), V1]]
} #join_mtd3
bench::mark(base(), data.table_0=mtd0(),
jm=join_mtd(), jm2=join_mtd2(), jm3=join_mtd2(), check=FALSE)
检查:
baseans <- setDT(base())
data.table_0 <- mtd0()
ordbase <- setorder(copy(baseans), y, x)
jm <- join_mtd()
jm2 <- join_mtd2()
jm3 <- join_mtd3()
identical(baseans, data.table_0)
#[1] TRUE
identical(ordbase, setorder(jm, y, x))
#[1] TRUE
identical(ordbase, setorder(jm2, y, x))
#[1] TRUE
identical(ordbase, setorder(jm3, y, x))
#[1] TRUE
时间:
# A tibble: 5 x 14
expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time result memory time gc
<chr> <bch:tm> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <bch:tm> <list> <list> <list> <list>
1 base() 38.59s 38.59s 38.59s 38.59s 0.0259 27.3GB 308 1 38.59s <data.frame [632,329 x ~ <Rprofmem [43,206 x ~ <bch:t~ <tibble [1 x ~
2 data.table_0 24.65s 24.65s 24.65s 24.65s 0.0406 14GB 159 1 24.65s <data.table [632,329 x ~ <Rprofmem [72,459 x ~ <bch:t~ <tibble [1 x ~
3 jm 1.28s 1.28s 1.28s 1.28s 0.779 75MB 7 1 1.28s <data.table [632,329 x ~ <Rprofmem [2,418 x 3~ <bch:t~ <tibble [1 x ~
4 jm2 1.44s 1.44s 1.44s 1.44s 0.696 62.5MB 9 1 1.44s <data.table [632,329 x ~ <Rprofmem [1,783 x 3~ <bch:t~ <tibble [1 x ~
5 jm3 1.57s 1.57s 1.57s 1.57s 0.636 62.5MB 9 1 1.57s <data.table [632,329 x ~ <Rprofmem [178 x 3]> <bch:t~ <tibble [1 x ~
数据:
library(data.table)
library(bench)
set.seed(1L)
nr <- 10e6/10
ni <- 10e3/10
df <- data.frame(x = sample(nr, size = nr, replace = TRUE),
y = sample(ni, size = nr, replace = TRUE))
dt <- data.table(df)
DT0 <- copy(dt)
DT <- copy(dt)
DT2 <- copy(dt)
y_unique <- sort(unique(df$y))
y_list <- setNames(rep(list(list()), length(y_unique)), y_unique)