この質問には 2 つの難しい部分があると思います。1 つ目は、重なりを見つけることです。BioconductorIRanges
のパッケージを使用します(基本パッケージも役立つ場合があります)。?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] ]