Finding overlap in ranges with R

后端 未结 6 891
面向向阳花
面向向阳花 2020-12-01 05:13

I have two data.frames each with three columns: chrom, start & stop, let\'s call them rangesA and rangesB. For each row of rangesA, I\'m looking to find which (if any)

相关标签:
6条回答
  • 2020-12-01 05:14

    The data.table package has a function foverlaps() which is capable of merging over interval ranges since 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() converts data.frame to data.table by reference

    • setkey() sorts the data.table by the columns provided (in this case all columns, since we did not provide any), and marks those columns as sorted, which we'll use later to perform the join on.

    • foverlaps() does the overlapping join efficiently. See this answer for a detailed explanation and comparison to other approaches.

    0 讨论(0)
  • 2020-12-01 05:16

    For your example data:

    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)
    )
    

    This will do it with sapply, such that each column is one row in rangesA and each row is corresponding row in rangesB:

    > 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
    
    0 讨论(0)
  • 2020-12-01 05:21

    Use the IRanges/GenomicRanges packages from Bioconductor, which is made for dealing with these exact problems (and scales massively)

    source("http://bioconductor.org/biocLite.R")
    biocLite("IRanges")
    

    There are a few appropriate containers for ranges on different chromosomes, one is 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
    
    0 讨论(0)
  • 2020-12-01 05:29

    RangesA and RangesB are clearly BED syntax, this can be done outside R in the command line with BEDtools, extremely fast and flexible with a dozen other options to work with genomic intervals. Then put the results back again into R.

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

    0 讨论(0)
  • 2020-12-01 05:40

    I add the dplyr solution.

    library(dplyr)
    inner_join(rangesA, rangesB, by="chrom") %>% 
      filter(start.y < start.x | stop.y > stop.x)
    

    Output:

      chrom start.x stop.x start.y stop.y
    1     5     100    105      99    106
    2     1     200    250     200    265
    
    0 讨论(0)
  • 2020-12-01 05:41

    This would be a lot easier / faster if you can merge the two objects first.

    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
    
    0 讨论(0)
提交回复
热议问题