我们假设我有以下数据:
set.seed(1)
test <- data.frame(letters=rep(c("A","B","C","D"),10), numbers=sample(1:50, 40, replace=TRUE))
我想知道其中A
的字母数不在B
中的数字,B
中有多少C
不在split
中,依此类推。
我使用基本函数mapply
和s.test <-split(test, test$letters)
notIn <- mapply(function(x,y) sum(!s.test[[x]]$numbers %in% s.test[[y]]$numbers), x=names(s.test)[1:3], y=names(s.test)[2:4])
想出了一个解决方案:
> notIn
A B C
9 7 7
给出了:
dplyr
但我也希望data.table
或{{1}}执行此操作。有可能吗?
答案 0 :(得分:4)
瓶颈似乎在split
。当模拟200组和每组150,000次观察时,split
在总共54秒内需要50秒。
使用split
可以大大加快data.table
步骤,如下所示。
## test is a data.table here
s.test <- test[, list(list(.SD)), by=letters]$V1
以下是使用data.table
+ mapply
维度数据的基准:
## generate data
set.seed(1L)
k = 200L
n = 150000L
test <- data.frame(letters=sample(paste0("id", 1:k), n*k, TRUE),
numbers=sample(1e6, n*k, TRUE), stringsAsFactors=FALSE)
require(data.table) ## latest CRAN version is v1.9.2
setDT(test) ## convert to data.table by reference (no copy)
system.time({
s.test <- test[, list(list(.SD)), by=letters]$V1 ## split
setattr(s.test, 'names', unique(test$letters)) ## setnames
notIn <- mapply(function(x,y)
sum(!s.test[[x]]$numbers %in% s.test[[y]]$numbers),
x=names(s.test)[1:199], y=names(s.test)[2:200])
})
## user system elapsed
## 4.840 1.643 6.624
对于您最大的数据维度,这大约是7.5倍的加速。这会足够吗?
答案 1 :(得分:4)
这似乎提供与data.table相同的加速,但只使用基数R.而不是拆分数据框,它只拆分数字列(在标记为##的行中):
## generate data - from Arun's post
set.seed(1L)
k = 200L
n = 150000L
test <- data.frame(letters=sample(paste0("id", 1:k), n*k, TRUE),
numbers=sample(1e6, n*k, TRUE), stringsAsFactors=FALSE)
system.time({
s.numbers <- with(test, split(numbers, letters)) ##
notIn <- mapply(function(x,y)
sum(!s.numbers[[x]] %in% s.numbers[[y]]),
x=names(s.numbers)[1:199], y=names(s.numbers)[2:200])
})