如何在多个列和多个条件下有效地合并 2 个数据框
How to efficiently merge 2 dataframes on multiple columns and on multiple conditions
我有 2 个 R 数据框,每个都有超过一百万行的基因组坐标,需要找出哪一个重叠(任意数量)。因此,我需要知道 df1.chr = df2.chr 和 df1.start(或 df1.end)在 df2.start 和 df2.end 之间的行或其中 df2.start(或 df2.end)介于 df1.start 和 df1.end 之间。如果这样可以让算法更简单,我真的只需要重叠多少,不一定是哪一个。
示例数据框 1
df1 <- data.frame("chr" = c("chr1", "chr1", "chr2", "chr3", "chr3"),
"start" = c(32826450, 49416884, 49417450, 49417523, 144385631),
"end" = c(32826456, 49416890, 49417456, 49417529, 144385637))
示例数据框 2
df2 <- data.frame("chr" = c("chr1", "chr1", "chr2"),
"start" = c(32826455, 45259551, 49417440),
"end" = c(32826458, 45259557, 49417453))
使用 sqldf 我可以很容易地获得答案
sqldf("SELECT *
FROM df1
JOIN df2
ON
df1.chr = df2.chr and
((df1.start BETWEEN df2.start and df2.end or
df1.end BETWEEN df2.start and df2.end) or
(df2.start BETWEEN df1.start and df1.end or
df2.end BETWEEN df1.start and df1.end))")
获得
chr start end chr..4 start..5 end..6
1 chr1 32826450 32826456 chr1 32826455 32826458
2 chr2 49417450 49417456 chr2 49417440 49417453
但这需要几个小时才能完成。
有没有更有效的方法进行?我试着同时查看 dplyr 和 data.table,但始终无法让所有部件正常工作。
谢谢!
使用生物导体库 GenomicRanges 可能更容易完成此任务。
df1 <- makeGRangesFromDataFrame(df1)
df2 <- makeGRangesFromDataFrame(df2)
> sum(countOverlaps(df1, df2))
[1] 2
HelloRanges 是关于如何在 GRanges 上执行常见任务的重要资源。
可能是这样的:
library(data.table)
setDT(df1)
setDT(df2)
cols <- c("chr","i.start","i.end","x.start","x.end")
unique(rbindlist(list(
df2[df1, on=.(chr, start<=start, end>=start), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=end, end>=end), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=start, end>=start), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=end, end>=end), nomatch=0L, mget(cols)]
)))
输出:
chr i.start i.end x.start x.end
1: chr2 49417450 49417456 49417440 49417453
2: chr1 32826450 32826456 32826455 32826458
我有 2 个 R 数据框,每个都有超过一百万行的基因组坐标,需要找出哪一个重叠(任意数量)。因此,我需要知道 df1.chr = df2.chr 和 df1.start(或 df1.end)在 df2.start 和 df2.end 之间的行或其中 df2.start(或 df2.end)介于 df1.start 和 df1.end 之间。如果这样可以让算法更简单,我真的只需要重叠多少,不一定是哪一个。
示例数据框 1
df1 <- data.frame("chr" = c("chr1", "chr1", "chr2", "chr3", "chr3"),
"start" = c(32826450, 49416884, 49417450, 49417523, 144385631),
"end" = c(32826456, 49416890, 49417456, 49417529, 144385637))
示例数据框 2
df2 <- data.frame("chr" = c("chr1", "chr1", "chr2"),
"start" = c(32826455, 45259551, 49417440),
"end" = c(32826458, 45259557, 49417453))
使用 sqldf 我可以很容易地获得答案
sqldf("SELECT *
FROM df1
JOIN df2
ON
df1.chr = df2.chr and
((df1.start BETWEEN df2.start and df2.end or
df1.end BETWEEN df2.start and df2.end) or
(df2.start BETWEEN df1.start and df1.end or
df2.end BETWEEN df1.start and df1.end))")
获得
chr start end chr..4 start..5 end..6
1 chr1 32826450 32826456 chr1 32826455 32826458
2 chr2 49417450 49417456 chr2 49417440 49417453
但这需要几个小时才能完成。
有没有更有效的方法进行?我试着同时查看 dplyr 和 data.table,但始终无法让所有部件正常工作。
谢谢!
使用生物导体库 GenomicRanges 可能更容易完成此任务。
df1 <- makeGRangesFromDataFrame(df1)
df2 <- makeGRangesFromDataFrame(df2)
> sum(countOverlaps(df1, df2))
[1] 2
HelloRanges 是关于如何在 GRanges 上执行常见任务的重要资源。
可能是这样的:
library(data.table)
setDT(df1)
setDT(df2)
cols <- c("chr","i.start","i.end","x.start","x.end")
unique(rbindlist(list(
df2[df1, on=.(chr, start<=start, end>=start), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=end, end>=end), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=start, end>=start), nomatch=0L, mget(cols)],
df2[df1, on=.(chr, start<=end, end>=end), nomatch=0L, mget(cols)]
)))
输出:
chr i.start i.end x.start x.end
1: chr2 49417450 49417456 49417440 49417453
2: chr1 32826450 32826456 32826455 32826458