[英]Finding overlap in ranges with R
我有兩個 data.frames,每個都有三列:chrom、start 和 stop,我們稱它們為 rangeA 和 rangeB。 對於 rangeA 的每一行,我正在尋找 rangeB 中的哪一行(如果有的話)完全包含 rangeA 行 - 我的意思是rangesAChrom == rangesBChrom, rangesAStart >= rangesBStart and rangesAStop <= rangesBStop
。
現在我正在做以下事情,我只是不太喜歡。 請注意,由於其他原因,我正在遍歷 rangeA 的行,但這些原因都不是什么大問題,鑒於此特定解決方案,它最終只會使事情更具可讀性。
范圍A:
chrom start stop
5 100 105
1 200 250
9 275 300
范圍B:
chrom start stop
1 200 265
5 99 106
9 275 290
對於 rangeA 中的每一行:
matches <- which((rangesB[,'chrom'] == rangesA[row,'chrom']) &&
(rangesB[,'start'] <= rangesA[row, 'start']) &&
(rangesB[,'stop'] >= rangesA[row, 'stop']))
我認為必須有更好的(更好,我的意思是在 rangeA 和 rangeB 的大型實例上更快)的方法來做到這一點,而不是循環遍歷這個構造。 有任何想法嗎?
使用 Bioconductor 的 IRanges/GenomicRanges 包,它是為處理這些確切問題(並大規模擴展)而設計的
source("http://bioconductor.org/biocLite.R")
biocLite("IRanges")
對於不同染色體上的范圍,有幾個合適的容器,一個是 RangesList
library(IRanges)
rangesA <- split(IRanges(rangesA$start, rangesA$stop), rangesA$chrom)
rangesB <- split(IRanges(rangesB$start, rangesB$stop), rangesB$chrom)
#which rangesB wholly contain at least one rangesA?
ov <- countOverlaps(rangesB, rangesA, type="within")>0
如果您可以先合並兩個對象,這將更容易/更快。
ranges <- merge(rangesA,rangesB,by="chrom",suffixes=c("A","B"))
ranges[with(ranges, startB <= startA & stopB >= stopA),]
# chrom startA stopA startB stopB
#1 1 200 250 200 265
#2 5 100 105 99 106
data.table
包有一個函數foverlaps()
,它能夠合並自 v1.9.4 以來的區間范圍:
require(data.table)
setDT(rangesA)
setDT(rangesB)
setkey(rangesB)
foverlaps(rangesA, rangesB, type="within", nomatch=0L)
# chrom start stop i.start i.stop
# 1: 5 99 106 100 105
# 2: 1 200 265 200 250
setDT()
通過引用將 data.frame 轉換為 data.table
setkey()
按提供的列(在本例中為所有列,因為我們沒有提供任何列setkey()
對 data.table 進行排序,並將這些列標記為已排序,稍后我們將使用它來執行連接。
foverlaps()
有效地進行重疊連接。 有關詳細說明以及與其他方法的比較,請參閱此答案。
RangesA 和 RangesB 顯然是 BED 語法,這可以在 R 之外使用 BEDtools 在命令行中完成,非常快速和靈活,有十幾個其他選項來處理基因組間隔。 然后將結果再次放回 R 中。
我添加了dplyr
解決方案。
library(dplyr)
inner_join(rangesA, rangesB, by="chrom") %>%
filter(start.y < start.x | stop.y > stop.x)
輸出:
chrom start.x stop.x start.y stop.y
1 5 100 105 99 106
2 1 200 250 200 265
對於您的示例數據:
rangesA <- data.frame(
chrom = c(5, 1, 9),
start = c(100, 200, 275),
stop = c(105, 250, 300)
)
rangesB <- data.frame(
chrom = c(1, 5, 9),
start = c(200, 99, 275),
stop = c(265, 106, 290)
)
這將使用sapply
,這樣每一列都是 rangeA 中的一行,而每一行都是 rangeB 中的對應行:
> sapply(rangesA$stop, '>=', rangesB$start) & sapply(rangesA$start, '<=', rangesB$stop)
[,1] [,2] [,3]
[1,] FALSE TRUE FALSE
[2,] TRUE FALSE FALSE
[3,] FALSE FALSE TRUE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.