【问题标题】:Collapse intersecting regions折叠相交区域
【发布时间】:2013-06-02 04:16:42
【问题描述】:

我正在尝试找到一种方法来折叠具有相交范围的行,由“开始”和“停止”列表示,并将折叠的值记录到新列中。例如我有这个数据框:

my.df<- data.frame(chrom=c(1,1,1,1,14,16,16), name=c("a","b","c","d","e","f","g"), start=as.numeric(c(0,70001,70203,70060, 40004, 50000872, 50000872)), stop=as.numeric(c(71200,71200,80001,71051, 42004, 50000890, 51000952)))


chrom name  start   stop
 1    a        0    71200
 1    b    70001    71200
 1    c    70203    80001
 1    d    70060    71051
14    e    40004    42004
16    f 50000872 50000890
16    g 50000872 51000952

我正在尝试查找重叠范围并记录“开始”和“停止”中折叠的重叠行所覆盖的最大范围以及折叠行的名称,所以我会得到这个:

chrom start   stop      name
 1    70001    80001    a,b,c,d
14    40004    42004    e
16    50000872 51000952 f,g

我想我可以像这样使用包 IRanges:

library(IRanges)
ranges <- split(IRanges(my.df$start, my.df$stop), my.df$chrom)

但是我在获取折叠列时遇到了麻烦:我尝试过使用 findOvarlaps 但是这个

ov <- findOverlaps(ranges, ranges, type="any")

但我认为这是不对的。

任何帮助将不胜感激。

【问题讨论】:

  • 我通过在开始 0 处添加第一个位置来编辑文本以更好地反映数据。使用任何一种方法建议 chrom 14 未正确分组,您能帮我理解为什么吗?谢谢!

标签: r bioinformatics overlap


【解决方案1】:

IRanges 是这样工作的好人选。无需使用 chrom 变量。

ir <- IRanges(my.df$start, my.df$stop)
## I create a new grouping variable Note the use of reduce here(performance issue)
my.df$group2 <- subjectHits(findOverlaps(ir, reduce(ir)))
# chrom name    start     stop group2
# 1     1    a    70001    71200      2
# 2     1    b    70203    80001      2
# 3     1    c    70060    71051      2
# 4    14    d    40004    42004      1
# 5    16    e 50000872 50000890      3
# 6    16    f 50000872 51000952      3

新的 group2 变量是范围指示器。现在使用 data.table 我无法将我的数据转换为所需的输出:

library(data.table)
DT <- as.data.table(my.df)
DT[, list(start=min(start),stop=max(stop),
         name=list(name),chrom=unique(chrom)),
               by=group2]

# group2    start     stop  name chrom
# 1:      2    70001    80001 a,b,c     1
# 2:      1    40004    42004     d    14
# 3:      3 50000872 51000952   e,f    16

PS:这里折叠的变量名不是字符串,而是因子的列表。例如,这比使用粘贴的折叠字符更有效且更容易访问。

EDIT OP澄清后,我将通过chrom创建组变量。我的意思是现在为每个 chrom 组调用 Iranges 代码。我稍微修改了您的数据,以创建相同染色体的间隔组。

my.df<- data.frame(chrom=c(1,1,1,1,14,16,16), 
                   name=c("a","b","c","d","e","f","g"),
                   start=as.numeric(c(0,3000,70203,70060, 40004, 50000872, 50000872)), 
                   stop=as.numeric(c(1,5000,80001,71051, 42004, 50000890, 51000952)))

library(data.table)
DT <- as.data.table(my.df)

## find interval for each chromsom
DT[,group := { 
      ir <-  IRanges(start, stop);
       subjectHits(findOverlaps(ir, reduce(ir)))
      },by=chrom]

## Now I group by group and chrom 
DT[, list(start=min(start),stop=max(stop),name=list(name),chrom=unique(chrom)),
   by=list(group,chrom)]

  group chrom    start     stop name chrom
1:     1     1        0        1    a     1
2:     2     1     3000     5000    b     1
3:     3     1    70060    80001  c,d     1
4:     1    14    40004    42004    e    14
5:     1    16 50000872 51000952  f,g    16

【讨论】:

  • @storaged 是的,非常好。要安装它,您应该执行以下操作source("http://bioconductor.org/biocLite.R") biocLite("IRanges")
  • 我编辑了正文以更好地反映我的数据框,我的起始位置也为 0,如果我应用它,我不会得到正确的重叠......我做错了什么?
  • @user971102 我编辑我的答案。我认为创建 0 的问题在于您创建了一个包含其他人的大区间...
  • @agstudy,谢谢,这也很好用!!这两种方法现在都给出了正确的答案,非常感谢!
  • 使用 GenomicRanges 包中的GRanges 在这里是有意义的——gr &lt;- GRanges(my.df$chrom, IRanges(my.df$start, my.df$stop))——然后使用gr 而不是答案中的ir。不妨将分组变量分配给 GRanges gr$group &lt;- ...,或者甚至更好地将 GRanges 拆分为 GRangesList split(gr, subjectHits(findOverlaps(gr, reduce(gr)))),这可能看起来有点“重”,但实际上内存效率相对较高。
【解决方案2】:

对数据进行排序后,可以很方便地测试一个区间是否与前一个区间重叠, 并为每组重叠间隔分配一个标签。 获得这些标签后,您可以使用ddply 来聚合数据。

d <- data.frame(
  chrom = c(1,1,1,14,16,16), 
  name  = c("a","b","c","d","e","f"), 
  start = as.numeric(c(70001,70203,70060, 40004, 50000872, 50000872)), 
  stop  = as.numeric(c(71200,80001,71051, 42004, 50000890, 51000952))
)

# Make sure the data is sorted
d <- d[ order(d$start), ]

# Check if a record should be linked with the previous
d$previous_stop <- c(NA, d$stop[-nrow(d)])
d$previous_stop <- cummax(ifelse(is.na(d$previous_stop),0,d$previous_stop))
d$new_group <- is.na(d$previous_stop) | d$start >= d$previous_stop

# The number of the current group of records is the number of times we have switched to a new group
d$group <- cumsum( d$new_group )

# We can now aggregate the data
library(plyr)
ddply( 
  d, "group", summarize, 
  start=min(start), stop=max(stop), name=paste(name,collapse=",")
)
#   group    start     stop    name
# 1     1        0    80001 a,d,c,b
# 2     2 50000872 51000952     e,f

但这忽略了chrom 列:为了解决这个问题,您可以分别对每个染色体执行相同的操作。

d <- d[ order(d$chrom, d$start), ]
d <- ddply( d, "chrom", function(u) { 
  x <- c(NA, u$stop[-nrow(u)])
  y <- ifelse( is.na(x), 0, x )
  y <- cummax(y)
  y[ is.na(x) ] <- NA
  u$previous_stop <- y
  u
} )
d$new_group <- is.na(d$previous_stop) | d$start >= d$previous_stop
d$group <- cumsum( d$new_group )
ddply( 
  d, .(chrom,group), summarize, 
  start=min(start), stop=max(stop), name=paste(name,collapse=",")
)
#   chrom group    start     stop  name
# 1     1     1        0    80001 a,c,b
# 2    14     2    40004    42004     d
# 3    16     3 50000872 51000952   e,f

【讨论】:

  • 谢谢,我也有 d$start 0,如果我接受这个,它似乎会弄乱一切,并使用这段代码以一种奇怪的方式对其进行分组......(我只是编辑了正文以反映这种奇怪的行为..)
  • 我的代码只检查记录是否应该与前一个链接,而不是以前的。这应该是固定的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
相关资源
最近更新 更多