R 在data.table的定义行数中操作
我正在使用一个数据表,该表包含多组数据,每个数据表包含一个位置(从-1000到+1000)和每个位置的计数。一个小例子如下所示:R 在data.table的定义行数中操作,r,aggregate,data.table,plyr,summarization,R,Aggregate,Data.table,Plyr,Summarization,我正在使用一个数据表,该表包含多组数据,每个数据表包含一个位置(从-1000到+1000)和每个位置的计数。一个小例子如下所示: dt.ex <- data.table(newID=rep(c("A","B"), each = 6), pos=rep(c(-2:3), 2), count= sample(c(1:100), 12)) newID pos count 1: A -2 29 2: A -1 32 3: A 0 33
dt.ex <- data.table(newID=rep(c("A","B"), each = 6), pos=rep(c(-2:3), 2), count= sample(c(1:100), 12))
newID pos count
1: A -2 29
2: A -1 32
3: A 0 33
4: A 1 45
5: A 2 51
6: A 3 26
7: B -2 22
8: B -1 79
9: B 0 2
10: B 1 48
11: B 2 87
12: B 3 38
老实说,我不知道如何在不使用某种循环的情况下开始,这对于67094000 x 3的桌子是不可取的。如果我只想计算每一个newID,那么类似的方法可以解决这个问题,但我还没有找到一个接近于回答我的问题的解决方案。Plyr解决方案也很受欢迎,尽管我觉得这可能太慢了。试试这个:
dt.ex[, .SD[, list(pos = mean(pos), count = sum(count)),
by = seq(0, .N-1) %/% 3],
by = newID]
请注意,父数据.table
的.N
用于嵌套的by
,因为.N
仅存在于j表达式中
另一种方法(不使用.SD
)是:
dt.ex[, seq := (seq_len(.N)-1) %/% 3, by=newID][,
list(pos = mean(pos), count=sum(count)), list(newID, seq)]
(相对)较大数据的基准测试:
set.seed(45)
get_grps <- function() paste(sample(letters, 5, TRUE), collapse="")
grps <- unique(replicate(1e4, get_grps()))
dt.in <- data.table(newID = sample(grps, 6e6, TRUE),
pos = sample(-1000:1000, 6e6, TRUE),
count = runif(6e6))
setkey(dt.in, newID)
require(microbenchmark)
eddi <- function(dt) {
dt[, .SD[, list(pos = mean(pos), count = sum(count)),
by = seq(0, .N-1) %/% 3], by = newID]
}
arun <- function(dt) {
dt[, seq := (seq_len(.N)-1) %/% 3, by=newID][,
list(pos = mean(pos), count=sum(count)), list(newID, seq)]
}
microbenchmark(o1 <- eddi(copy(dt.in)), o2 <- arun(copy(dt.in)), times=2)
Unit: seconds
expr min lq median uq max neval
o1 <- eddi(copy(dt.in)) 25.23282 25.23282 26.16009 27.08736 27.08736 2
o2 <- arun(copy(dt.in)) 13.59597 13.59597 14.41190 15.22783 15.22783 2
set.seed(45)
在您的输出中获取GRP,您没有pos
的平均值,而是最低/第一个值…?您的数据中有多少唯一的newID
s?使用.SD
会更慢,因为唯一的newID
的数量增加且n
较小(导致太多分组)<代码>dt[,seq:=(seq_len(.N)-1)%/%3,by=newID][,list(pos=mean(pos),count=sum(count)),list(newID,seq)]将相对更快。在600万行上,.SD
需要26秒,而另一行需要12秒。@Arun我的测试不是这样,但你应该自己测试它;嗯,我想是的-这对我来说很奇怪,反过来说,我会贴一张bench@Arun没关系,你说得对,我想字母太少了newID
s的数量不能说明你的观点.SD
版本启动速度更快,但扩展速度不好all@Arun我可以看到你删除的答案,它看起来很有用+1取消删除。@MatthewDowle,确定取消删除。你完全正确。在mac上的1e4通话中,seq
和seq_len
之间大约有1秒的差异(对于1e5通话,1分钟,30秒对90秒)。
set.seed(45)
get_grps <- function() paste(sample(letters, 5, TRUE), collapse="")
grps <- unique(replicate(1e4, get_grps()))
dt.in <- data.table(newID = sample(grps, 6e6, TRUE),
pos = sample(-1000:1000, 6e6, TRUE),
count = runif(6e6))
setkey(dt.in, newID)
require(microbenchmark)
eddi <- function(dt) {
dt[, .SD[, list(pos = mean(pos), count = sum(count)),
by = seq(0, .N-1) %/% 3], by = newID]
}
arun <- function(dt) {
dt[, seq := (seq_len(.N)-1) %/% 3, by=newID][,
list(pos = mean(pos), count=sum(count)), list(newID, seq)]
}
microbenchmark(o1 <- eddi(copy(dt.in)), o2 <- arun(copy(dt.in)), times=2)
Unit: seconds
expr min lq median uq max neval
o1 <- eddi(copy(dt.in)) 25.23282 25.23282 26.16009 27.08736 27.08736 2
o2 <- arun(copy(dt.in)) 13.59597 13.59597 14.41190 15.22783 15.22783 2