代码之家  ›  专栏  ›  技术社区  ›  dan

快速查找线性区间重叠的方法

  •  0
  • dan  · 技术社区  · 4 年前

    我有一个 data.frame 线性间隔(映射RNA序列读取的基因组坐标),例如:

    df <- data.frame(seqnames = c(rep("chr10",2),rep("chr5",8)),
                     start = c(12255935,12257004,12243635,12244009,12253879,12254395,12254506,12255142,12255229,12258719),
                     end = c(12257002,12258512,12243764,12244291,12254107,12254501,12254515,12255535,12255312,12258764),
                     read_id = c(rep("R9",2),rep("R10",8)),
                     stringsAsFactors = F)
    

    对于某些读取,在相同读取的其他读取中包含或相交的间隔,我想合并它们。在上面的例子中 read_id = "R10" ,时间间隔: chr5 12255229 12255312 被控制在间隔内 chr5 12255142 12255535 .

    一读 数据框架 ,我使用以下程序:

    #defining helper functions
    clusterHits <- function(overlap.hits)
    {
      overlap.hits <- GenomicRanges::union(overlap.hits,t(overlap.hits))
      query.hits <- S4Vectors::queryHits(overlap.hits)
      search.hits <- S4Vectors::subjectHits(overlap.hits)
      cluster.ids <- seq_len(S4Vectors::queryLength(overlap.hits))
      while(TRUE){
        hit <- S4Vectors::Hits(query.hits,cluster.ids[search.hits],S4Vectors::queryLength(overlap.hits),S4Vectors::subjectLength(overlap.hits))
        tmp.cluster.ids <- pmin(cluster.ids,S4Vectors::selectHits(hit,"first"))
        if(identical(tmp.cluster.ids,cluster.ids))
          break
        cluster.ids <- tmp.cluster.ids
      }
      unname(S4Vectors::splitAsList(seq_len(S4Vectors::queryLength(overlap.hits)),cluster.ids))
    }
    
    mergeConnectedRanges <- function(x.gr,overlap.hits)
    {
      cluster.ids <- clusterHits(overlap.hits)
      merged.gr <- range(IRanges::extractList(x.gr,cluster.ids))
      merged.gr <- unlist(merged.gr)
      S4Vectors::mcols(merged.gr)$merged.idx <- cluster.ids
      return(merged.gr)
    }
    
    #Now separate R10 and merge its intervals
    df1 <- dplyr::filter(df, read_id == "R10")
    gr <- GenomicRanges::GRanges(dplyr::select(df1,seqnames,start,end))
    redundant.intervals <- GenomicRanges::findOverlaps(gr,ignore.strand=T)
    query.gr <- redundant.intervals[S4Vectors::queryHits(redundant.intervals)]
    subject.gr <- redundant.intervals[S4Vectors::subjectHits(redundant.intervals)]
    as.data.frame(mergeConnectedRanges(x.gr=gr,overlap.hits=redundant.intervals))
    

    它给出:

      seqnames    start      end width strand merged.idx
    1     chr5 12243635 12243764   130      *          1
    2     chr5 12244009 12244291   283      *          2
    3     chr5 12253879 12254107   229      *          3
    4     chr5 12254395 12254501   107      *          4
    5     chr5 12254506 12254515    10      *          5
    6     chr5 12255142 12255535   394      *       6, 7
    7     chr5 12258719 12258764    46      *          8
    

    所以 merged.idx 显示间隔6和7英寸 df1 已经合并。

    我正在寻找一种跨越数千次阅读的快速方法。显而易见的方法是使用 do.call 穿过独特的阅读区 df :

    library(dplyr)
    do.call(rbind, lapply(unique(df$read_id), function(r){
      read.df <- dplyr::filter(df, read_id == r)
      gr <- GenomicRanges::GRanges(dplyr::select(read.df,seqnames,start,end))
      redundant.intervals <- GenomicRanges::findOverlaps(gr,ignore.strand=T)
      query.gr <- redundant.intervals[S4Vectors::queryHits(redundant.intervals)]
      subject.gr <- redundant.intervals[S4Vectors::subjectHits(redundant.intervals)]
      as.data.frame(mergeConnectedRanges(x.gr=gr,overlap.hits=redundant.intervals)) %>%
        dplyr::mutate(read_id = r)
    }))
    

    0 回复  |  直到 4 年前
        1
  •  1
  •   Uwe    4 年前

    使用 GenomicRanges 来自 生物导体 这个任务可以通过几行代码来完成:

    library(GenomicRanges)
    makeGRangesListFromDataFrame(df, split.field = "read_id") |>
      reduce(with.revmap = TRUE) |>
      as.data.frame()
    
      group group_name seqnames    start      end width strand revmap
    1     1        R10     chr5 12243635 12243764   130      *      1
    2     1        R10     chr5 12244009 12244291   283      *      2
    3     1        R10     chr5 12253879 12254107   229      *      3
    4     1        R10     chr5 12254395 12254501   107      *      4
    5     1        R10     chr5 12254506 12254515    10      *      5
    6     1        R10     chr5 12255142 12255535   394      *   6, 7
    7     1        R10     chr5 12258719 12258764    46      *      8
    8     2         R9    chr10 12255935 12257002  1068      *      1
    9     2         R9    chr10 12257004 12258512  1509      *      2
    

    作为 GenomeRanges 包裹不在CRAN上,请看小插曲 Installing and Managing Bioconductor Packages 还是逃跑

    install.packages("BiocManager")
    BiocManager::install("GenomicRanges")
    

    数据

    df <- data.frame(seqnames = c(rep("chr10", 2), rep("chr5", 8)),
                     start = c(12255935, 12257004, 12243635, 12244009, 12253879, 12254395, 12254506, 12255142, 12255229, 12258719),
                     end   = c(12257002, 12258512, 12243764, 12244291, 12254107, 12254501, 12254515, 12255535, 12255312, 12258764),
                     read_id = c(rep("R9", 2), rep("R10", 8)), 
                     stringsAsFactors = FALSE)
    

    作为