应用涉及下一组的功能的小组汇总

时间:2014-03-23 01:11:37

标签: r dataframe data.table dplyr

我们假设我有以下数据:

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中,依此类推。

我使用基本函数mapplys.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}}执行此操作。有可能吗?

2 个答案:

答案 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])
})