我有一个长度为5,000,000的数字向量
>head(coordvec)
[1] 47286545 47286546 47286547 47286548 47286549 472865
和3 x 1,400,000数字矩阵
>head(subscores)
V1 V2 V3
1 47286730 47286725 0.830
2 47286740 47286791 0.065
3 47286750 47286806 -0.165
4 47288371 47288427 0.760
5 47288841 47288890 0.285
6 47288896 47288945 0.225
我想要完成的是,对于coordvec中的每个数字,找到子行中行的V3的平均值,其中V1和V2包含coordvec中的数字。为此,我采取以下方法:
results<-numeric(length(coordvec))
for(i in 1:length(coordvec)){
select_rows <- subscores[, 1] < coordvec[i] & subscores[, 2] > coordvec[i]
scores_subset <- subscores[select_rows, 3]
results[m]<-mean(scores_subset)
}
这很慢,需要几天才能完成。有更快的方法吗?
谢谢,
丹
答案 0 :(得分:6)
我认为这个问题有两个具有挑战性的部分。首先是找到重叠。我使用Bioconductor中的IRanges
包(基础包中的?findInterval
也可能有用)
library(IRanges)
创建表示坐标向量的宽度1范围,以及表示得分的范围集合;为方便起见,我对坐标向量进行排序,假设可以对重复的坐标进行相同的处理
coord <- sort(sample(.Machine$integer.max, 5000000))
starts <- sample(.Machine$integer.max, 1200000)
scores <- runif(length(starts))
q <- IRanges(coord, width=1)
s <- IRanges(starts, starts + 100L)
我们在这里找到哪个query
重叠subject
system.time({
olaps <- findOverlaps(q, s)
})
我的笔记本电脑大约需要7秒。有不同类型的重叠(请参阅?findOverlaps
),因此这一步可能需要进行一些改进。
结果是一对索引索引查询和重叠主题的向量。
> olaps
Hits of length 281909
queryLength: 5000000
subjectLength: 1200000
queryHits subjectHits
<integer> <integer>
1 19 685913
2 35 929424
3 46 1130191
4 52 37417
我认为这是第一个复杂部分的结束,找到281909重叠。 (我不认为其他地方提供的data.table答案可以解决这个问题,但我可能会弄错......)
下一个具有挑战性的部分是计算大量资金。内置方式类似于
olaps0 <- head(olaps, 10000)
system.time({
res0 <- tapply(scores[subjectHits(olaps0)], queryHits(olaps0), mean)
})
在我的电脑上需要大约3.25秒并且看起来线性缩放,因此280k的重叠可能是90秒。但我认为我们可以使用data.table
有效地完成此制表。原始坐标为start(v)[queryHits(olaps)]
,因此
require(data.table)
dt <- data.table(coord=start(q)[queryHits(olaps)],
score=scores[subjectHits(olaps)])
res1 <- dt[,mean(score), by=coord]$V1
所有280k重叠大约需要2.5秒。
通过识别查询命中是有序的,可以获得更高的速度。我们想要计算每次查询命中的平均值。我们首先创建一个变量来指示每个查询命中运行的结尾
idx <- c(queryHits(olaps)[-1] != queryHits(olaps)[-length(olaps)], TRUE)
然后计算每次运行结束时的累积分数,每次运行的长度,以及运行结束时和运行开始时的累积分数之间的差异
scoreHits <- cumsum(scores[subjectHits(olaps)])[idx]
n <- diff(c(0L, seq_along(idx)[idx]))
xt <- diff(c(0L, scoreHits))
最后,意思是
res2 <- xt / n
对于所有数据,这大约需要0.6秒,并且与data.table结果相同(虽然比?更加神秘?)
> identical(res1, res2)
[1] TRUE
对应于平均值的原始坐标是
start(q)[ queryHits(olaps)[idx] ]
答案 1 :(得分:2)
这样的事情可能会更快:
require(data.table)
subscores <- as.data.table(subscores)
subscores[, cond := V1 < coordvec & V2 > coordvec]
subscores[list(cond)[[1]], mean(V3)]
list(cond)[[1]]
因为:“当我是单个变量名时,它不被视为列名的表达式,而是在调用范围中进行评估。”来源:?data.table
答案 2 :(得分:0)
由于你的答案不容易重现,即使它是,你的subscores
都没有满足你的布尔条件,我不确定这是否完全符合你的要求,但你可以使用一个apply
家庭和一个功能。
myfun <- function(x) {
y <- subscores[, 1] < x & subscores[, 2] > x
mean(subscores[y, 3])
}
sapply(coordvec, myfun)
您还可以查看mclapply
。如果你有足够的内存,这可能会显着加快速度。但是,您也可以查看具有类似结果的foreach
包。您通过分配到for loop
而不是增长results
来确定{{1}}“正确”,但实际上,您正在进行很多的比较。很难加快这一点。