【发布时间】:2013-07-18 20:59:42
【问题描述】:
我正在寻找以下问题的更快解决方案。我将用一个小例子来说明这个问题,然后提供代码来模拟大数据,因为这就是这个问题的重点。我的实际问题大小是列表长度 = 100 万个条目。
说,我有两个列表,如下所示:
x <- list(c(82, 18), c(35, 50, 15))
y <- list(c(1,2,3,55,90), c(37,38,95))
x 和 y 的属性:
-
x列表中的每个元素总和为 100。 -
y的每个元素将始终进行排序,并且始终介于 1 和 100 之间。
问题:
现在,我想要的是这个。以x[[1]] 和y[[1]] 为例,我想在y[[1]] 中找到 1) 82 和 c(1,2,3,55),而介于 83 和 100 之间的数字是 c(90)。对于x[[2]] 和y[[2]],类似地,c(0, 2, 1)。也就是说,答案应该是:
[[1]]
[1] 4 1
[[2]]
[1] 0 2 1
如果这还不清楚,请告诉我。
具有 100 万个条目的模拟数据
set.seed(1)
N <- 100
n <- 1e6
len <- sample(2:3, n, TRUE)
x <- lapply(seq_len(n), function(ix) {
probs <- sample(100:1000, len[ix])
probs <- probs/sum(probs)
oo <- round(N * probs)
if (sum(oo) != 100) {
oo[1] <- oo[1] + (100 - sum(oo))
}
oo
})
require(data.table)
ss <- sample(1:10, n, TRUE)
dt <- data.table(val=sample(1:N, sum(ss), TRUE), grp=rep(seq_len(n), ss))
setkey(dt, grp, val)
y <- dt[, list(list(val)),by=grp]$V1
到目前为止我做了什么:
使用mapply(慢):
我想先将rank 与ties.method="first" 和mapply 一起使用(显然选择2 个列表)并尝试了这个:
tt1 <- mapply(y, x, FUN=function(a,b) {
tt <- rank(c(a, cumsum(b)), ties="first")[-(1:length(a))]; c(tt[1]-1, diff(tt)-1)
})
虽然这很好用,但 100 万个条目需要花费大量时间。我认为计算rank 和diff 的开销会增加很多次。这需要 241 秒!
因此,我决定尝试通过使用data.table 并使用“组”列进行排序来克服rank 和diff 的使用。我想出了一个更长但更快的解决方案,如下所示:
使用data.table(更快):
xl <- sapply(x, length)
yl <- sapply(y, length)
xdt <- data.table(val=unlist(x, use.names=FALSE), grp=rep(seq_along(xl), xl), type = "x")
xdt[, cumval := cumsum(val), by=grp]
ydt <- data.table(val=unlist(y, use.names=FALSE), grp=rep(seq_along(yl), yl), type = "y")
tt2 <-rbindlist(list(ydt, xdt[, list(cumval, grp, type)]))
setkey(tt2, grp, val)
xdt.pos <- which(tt2$type == "x")
tt2[, type.x := 0L][xdt.pos, type.x := xdt.pos]
tt2 <- tt2[xdt.pos][tt2[, .N, by = grp][, N := cumsum(c(0, head(N, -1)))]][, sub := type.x - N]
tt2[, val := xdt$val]
# time consuming step
tt2 <- tt2[, c(sub[1]-1, sub[2:.N] - sub[1:(.N-1)] - 1), by = grp]
tt2 <- tt2[, list(list(V1)),by=grp]$V1
这需要 26 秒。所以它快了大约 9 倍。我想知道是否有可能获得更多的加速,因为我必须在 5-10 个这样的 100 万个元素上递归地计算它。谢谢。
【问题讨论】:
-
你试过类似
hist(y[[k]],breaks=c(x[[k]][1:(n-1)],100) )的东西吗? -
卡尔,什么是 k,1 到 1e6?在大数据上给出 k=2 的错误。
-
在例子中:c(0, 2, 1),0从哪里来?我认为 2 = {50}
-
@ZoltánNagy,y 中 x 的计数在 1-35、36-85、86-100 之间。
-
阿伦,你有两个列表变量。由于您将
x[[1]]与y[[1]]进行匹配,x[[2]]与y[[2]]进行匹配,所以我假设您总是这样匹配。x[[2]]和y[[2]]在真实数据集中的值是多少?如果它们的长度为 1,那么hist可能会失败。
标签: r algorithm optimization data.table mapply