我有两个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的大型实例更快)这样做的方式比循环这个结构。有什么想法吗?
答案 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()
通过引用
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。
答案 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