在R中查找范围重叠

时间:2010-10-12 15:18:18

标签: r bioinformatics

我有两个data.frames,每个都有三列:chrom,start&amp;停止,让我们称它们为rangeA和rangesB。对于每行rangeA,我想找到rangeB中哪一行(如果有的话)完全包含rangesA行 - 我的意思是rangesAChrom == rangesBChrom, rangesAStart >= rangesBStart and rangesAStop <= rangesBStop

现在我正在做以下事情,我不太喜欢。请注意,由于其他原因,我正在循环遍历rangeA的行,但这些原因都不是什么大问题,它最终会使这些特定解决方案更具可读性。

rangesA:

chrom   start   stop
 5       100     105
 1       200     250
 9       275     300

rangesB:

chrom    start    stop
  1       200      265
  5       99       106
  9       275      290
对于rangesA中的每一行

matches <- which((rangesB[,'chrom']  == rangesA[row,'chrom']) &&
                 (rangesB[,'start'] <= rangesA[row, 'start']) &&
                 (rangesB[,'stop'] >= rangesA[row, 'stop']))

我认为必须更好(并且更好,我的意思是比大范围A和rangeB的大型实例更快)这样做的方式比循环这个结构。有什么想法吗?

6 个答案:

答案 0 :(得分:20)

使用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

答案 1 :(得分:13)

如果您可以先合并这两个对象,这将更容易/更快。

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

答案 2 :(得分:12)

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()按提供的列对data.table进行排序(在本例中为所有列,因为我们没有提供任何列),并将这些列标记为已排序,我们稍后会使用这些列执行加入。

  • foverlaps()有效地进行重叠连接。有关详细说明和与其他方法的比较,请参阅this answer

答案 3 :(得分:2)

对于您的示例数据:

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,这样每列都是一个范围A中的一行,每一行都是范围B中对应的行:

> 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

答案 4 :(得分:2)

RangesA和RangesB显然是BED语法,这可以在命令行中使用BEDtools在R外部完成,非常快速和灵活,还有十几种其他选项可用于基因组间隔。然后将结果重新放回R。

https://code.google.com/p/bedtools/

答案 5 :(得分:2)

我添加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