R或熊猫。如果df A中的列值在df B中2列给定的范围内,则打印A中的行

时间:2019-09-28 00:28:47

标签: r pandas dataframe

使用python熊猫或R:

我有一个数据框架A,具有数百万行:

CHR SNP POS
1 rs2073813 753541
1 rs3131969 754182
2 rs3131968 754192
2 rs3131967 754334
3 rs3115859 754503
3 rs3131966 900000

和另一个数据框B(也有数百万行):

CHR start end 
1 700500 833300
2 1000 20000
2 59998 60000 
3 700000 800000

对于A中的每个“ POS”,我要检查它是否存在于B的“开始”和“结束”给定的范围内(检查B中的每一行)。另外,A中的CHR也应与B中的CHR相匹配。如果满足这些条件,则在A中打印行。A中的行是唯一的,并根据A中的POS进行排序。B中的每一行也是唯一的。

例如,A的POS 753541处于700500到833300的范围内,A的CHR = 1和CHR = 1 B也匹配,因此打印:

1 rs2073813 753541

最后,我想获得一个像这样的数据帧C:

CHR SNP POS
1 rs2073813 753541
1 rs3131969 754182
3 rs3115859 754503

2 个答案:

答案 0 :(得分:1)

使用data.table设置示例数据:

library(data.table)
A <- data.table(CHR = c(1,1,2,2,3,3), SNP = c('rs2073813', 'rs3131969', 'rs3131968', 'rs3131967', 'rs3115859', 'rs3131966'), POS = c(753541,754182,754192,754334,754503,900000))
B <- data.table(CHR = c(1,2,2,3), start = c(700500, 1000, 59998, 700000), end = c(833300, 20000, 60000, 800000))

然后在A上合并BCHR

merged_all <- merge(x = A, y = B, on = 'CHR')

然后过滤合并的数据,使其仅包含满足您条件的行和列:

out <- merged_all[(POS > start & end > POS), .(CHR, SNP, POS)]
> out
   CHR       SNP    POS
1:   1 rs2073813 753541
2:   1 rs3131969 754182
3:   3 rs3115859 754503

编辑:

使用更有效的选项进行更新:

out <- A[B, on = .(CHR, POS >= start, POS <= end), .(CHR, SNP, POS), nomatch = 0]
> out
   CHR       SNP    POS
1:   1 rs2073813 700500
2:   1 rs3131969 700500
3:   3 rs3115859 700000

这将直接连接表。

注意:尚不清楚您是否需要包含范围或排除范围(>>=)。您可以据此进行调整。

答案 1 :(得分:1)

his edit, cddt has suggested中使用非等额联接

不幸的是,非等额联接有些棘手。为了产生预期的结果,我们需要告诉我们从第一个数据表中选择POS。表A

library(data.table)
setDT(A) # coerce to data.table
setDT(B) 
A[B, on = .(CHR, POS >= start, POS <= end), .(CHR, SNP, x.POS), nomatch = 0]
   CHR       SNP    POS
1:   1 rs2073813 753541
2:   1 rs3131969 754182
3:   3 rs3115859 754503

这是通过前缀x.

实现的

或者,(也许有些直观),我们可以通过以下方式返回匹配行的行索引:

A[B, on = .(CHR, POS >= start, POS <= end), nomatch = 0, which = TRUE]
[1] 1 2 5

和相应的子集A

A[A[B, on = .(CHR, POS >= start, POS <= end), nomatch = 0, which = TRUE]]
   CHR       SNP    POS
1:   1 rs2073813 753541
2:   1 rs3131969 754182
3:   3 rs3115859 754503

foverlaps()

这是一种不太优雅的选择:

foverlaps(A[, POS2 := POS], setkey(B), by.x = c("CHR", "POS", "POS2"), nomatch = 0)
   CHR  start    end       SNP    POS   POS2
1:   1 700500 833300 rs2073813 753541 753541
2:   1 700500 833300 rs3131969 754182 754182
3:   3 700000 800000 rs3115859 754503 754503

数据

library(data.table)

A <- fread("CHR SNP POS
1 rs2073813 753541
1 rs3131969 754182
2 rs3131968 754192
2 rs3131967 754334
3 rs3115859 754503
3 rs3131966 900000")

B <- fread("CHR start end 
1 700500 833300
2 1000 20000
2 59998 60000 
3 700000 800000")