检查一个 data.table 列中的所有元素以查看另一个 data.table 列中出现的每个值的最快方法
Posted
技术标签:
【中文标题】检查一个 data.table 列中的所有元素以查看另一个 data.table 列中出现的每个值的最快方法【英文标题】:Fastest way to check all elements in one data.table column for each value appearance in another data.table column 【发布时间】:2019-12-13 00:39:58 【问题描述】:如果每个值出现在不同的 data.table 列中,检查 data.table R 中的完整列的最快方法是什么?
示例问题:
创建示例大数据:
dt1 <- data.table(dt1row=c(1:1000000),code=sapply(c(1:1000000),FUN=function(x)paste(sample(letters,5), collapse="")))
dt2 <- data.table(dt2row=c(1:500000),code=sapply(c(1:500000),FUN=function(x)paste(sample(letters,5), collapse="")))
我想替换的慢功能(但有效):
#SLOW ON BIG DATA!
dt1$in_dt2 <- sapply(c(1:nrow(dt1)),FUN=function(x)dt1$code[x] %in% dt2$code)
【问题讨论】:
【参考方案1】:@thelatemail 目前有更快的方法:
setkey(dt1, code)
setkey(dt2, code)
dt1[, in_dt2 := FALSE][dt2, on=.(code), in_dt2 := TRUE]
我认为你正在寻找一个连接操作和设置键应该加快速度:
setkey(dt1, code)
setkey(dt2, code)
existing <- dt2[dt1, on=.(code), nomatch=0L]
dt1[, in_dt2 := dt1row %in% existing$dt1row]
base R 的另一个选项是使用base::match
m0 <- function()
DT10$in_dt2 <- match(DT10$code, dt2$code, nomatch=0L) > 0L
DT10
m1 <- function()
setkey(DT11, code)
existing <- dt2[DT11, on=.(code), nomatch=0L, mult="first"]
DT11[, in_dt2 := dt1row %in% existing$dt1row]
m2 <- function()
DT12[, in_dt2 := match(code, dt2$code, nomatch=0L) > 0L]
m_thelatemail <- function()
setkey(DT13, code)
DT13[, in_dt2 := FALSE][dt2, on=.(code), in_dt2 := TRUE]
bench::mark(m0(), m1(), m2(), m_thelatemail(), check=FALSE)
identical(DT11[order(dt1row), in_dt2], m0()$in_dt2)
identical(DT12[order(dt1row), in_dt2], m0()$in_dt2)
identical(DT13[order(dt1row), in_dt2], m0()$in_dt2)
#[1] TRUE
时间安排:
# A tibble: 4 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time gc
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list> <list> <list>
1 m0() 914ms 914ms 1.09 38.3MB 1.09 1 1 914ms <df[,3] [1,000,000 x 3]> <df[,3] [10 x 3]> <bch:tm> <tibble [1 x 3]>
2 m1() 252ms 273ms 3.66 36.8MB 1.83 2 1 547ms <df[,3] [1,000,000 x 3]> <df[,3] [33 x 3]> <bch:tm> <tibble [2 x 3]>
3 m2() 198ms 252ms 4.14 23.1MB 2.76 3 2 724ms <df[,3] [1,000,000 x 3]> <df[,3] [10 x 3]> <bch:tm> <tibble [3 x 3]>
4 m_thelatemail() 148ms 158ms 6.38 15.4MB 0 4 0 627ms <df[,3] [1,000,000 x 3]> <df[,3] [28 x 3]> <bch:tm> <tibble [4 x 3]>
m0()
的输出:
dt1row code in_dt2
1: 1 nydga FALSE
2: 2 bwknr FALSE
3: 3 sauxj FALSE
4: 4 vnjgi FALSE
5: 5 ouein FALSE
---
999996: 999996 wiucs FALSE
999997: 999997 yqjrp FALSE
999998: 999998 elort FALSE
999999: 999999 asjyh FALSE
1000000: 1000000 lmbjw FALSE
数据:
library(data.table)
set.seed(0L)
nr <- 1e6
dt1 <- data.table(dt1row=c(1:nr),code=sapply(c(1:nr),FUN=function(x) paste(sample(letters,5), collapse="")))
dt2 <- data.table(dt2row=c(1:(nr/2)),code=sapply(c(1:(nr/2)),FUN=function(x) paste(sample(letters,5), collapse="")))
DT10 <- copy(dt1)
DT11 <- copy(dt1)
DT12 <- copy(dt1)
DT13 <- copy(dt1)
setkey(dt2, code)
一个建议是set.seed
当数据是随机生成时使用sample
【讨论】:
优秀的答案。谢谢! 您也可以将作业作为连接的一部分 -dt1[, in_dt2 := FALSE];dt1[dt2, on=.(code), in_dt2 := TRUE]
setkey(dt1, code)
在我的机器上大约需要 6 秒。所以m2()
可以很好(或者是一个主要是糖dt1[, in_dt2 := code %in% dt2$code]
的轻微替代品)。以上是关于检查一个 data.table 列中的所有元素以查看另一个 data.table 列中出现的每个值的最快方法的主要内容,如果未能解决你的问题,请参考以下文章