如何匹配另一个数据集范围内的行

How to match rows within in a range of another dataset

我有一个遗传数据集,我在其中匹配 1 个文件的基因组中的染色体位置,前提是它们符合另一个文件中给定的染色体位置范围。

我试过类似的问题,主要是时间间隔,但由于我需要确保染色体数也匹配(所以我不匹配相同的位置但它们没有用)在不同的染色体上)

我的数据是这样的:

#df1 - chromosome positions to find within df2 ranges:

Chromosome   Position   Start   End
    1           101      101    101
    2           101      101    101
    3           600      600    600
#df2 - genomic ranges
Chromosome Start End      CpG
    1       50   200       10
    1       300  400        2
    4       100  200        5

预期的匹配输出(最终我也在寻找 df1 数据的匹配 CpG 列):

Chromosome   Position    Start   End   CpG
    1           101        50    200    10  #only row of df1 that's within a range on df2 on the same chromosome

我目前正在尝试使用:

df <-df1 %>%
  left_join(df2, 
            by = "Chromosome") %>% 
  filter(Position >= Start & Position <= End)

Error: Problem with `filter()` input `..1`.
x object 'Start' not found
i Input `..1` is `Position >= Start & Position <= End`.

我不明白我是怎么得到这个错误的,开始和结束列存在于两个文件中并且都是整数数据类 - 有没有我遗漏的东西或我可以解决的其他方法这个?

我的实际数据非常大,所以如果 data.table 解决方案适用于此,我也在尝试找到它 - 我试过了,但我是新手,还没有走得太远:

df1[df2, on = .(Chromosome, Position > End, Position < Start ) ]

编辑:尝试重叠:

setkey(df1)
df2[, End := Start]
foverlaps(df2, df1, by.x = names(df2), type = "within", mult = "all", nomatch = 0L)

Error in foverlaps(df2, df1, by.x = names(df2), type = "within", mult = "all",  : 
  length(by.x) != length(by.y). Columns specified in by.x should correspond to columns specified in by.y and should be of same lengths.

问题与 left_join() 相关,它将来自不同数据集的同名列堆叠在一个数据集中。由于同一数据集中的两列不能具有相同的列名,因此 Start 和 End 列的名称更改为 Start.x,并且 Start.y、End.x、End.y.

因此,您必须从第一个数据集中删除开始和结束列,如下所示:

library(data.table)
library(tidyr)
library(dplyr)
df1 <- fread("Chromosome   Position   Start   End
    1           101      101    101
             2           101      101    101
             3           600      600    600")
df2<- fread("Chromosome Start End      CpG
    1       50   200       10
    1       300  400        2
    4       100  200        5")

df <-df1 %>%select(Chromosome, Position)%>%
  left_join(df2, 
            by = "Chromosome") %>% 
  filter(Position >= Start & Position <= End)

或引用列的真实名称,然后删除多余的列:

df <-df1 %>%
  left_join(df2, 
            by = "Chromosome") %>% 
  filter(Position >= Start.y & Position <= End.y)

干杯!

对于 data.table 解决方案,您应该查看 Arun 在@Henrik 提供的 link 中关于非等值连接的第二个答案。 Overlap join with start and end positions

基于此,我们有

library(data.table)

df1 <- data.table(Chromosome=1:3,Position=c(101,101,600),
                  Start=c(101,101,600),End=c(101,101,600))

df2 <- data.table(Chromosome=c(1,1,4),
                  Start=c(50,300,100),End=c(200,400,200),CpG=c(10,2,5))

df1[df2,.(Chromosome,Position=x.Position,Start,End,CpG),
    on=.(Chromosome,Position>=Start,Position<=End),nomatch=0L]

给予

       Chromosome Position Start End CpG
1:              1      101   101 101  10

这不太正确,因为它需要 StartEnd 来自 df1 而不是 df2。为什么 df1 中还有 StartEnd

一种处理方法是不将它们包含在连接语句中:

df1[,.(Chromosome,Position)][df2,
    .(Chromosome,Position=x.Position,Start,End,CpG),
   on=.(Chromosome,Position>=Start,Position<=End),nomatch=0L]

给予

   Chromosome Position Start End CpG
1:          1      101    50 200  10

[编辑以注意@Carles Sans Fuentes 在他的 dplyr 回答中发现了同样的问题。]

为了检查更多匹配的案例,我添加了更多数据:

 df1 <- data.table(Chromosome=c(1,1:4),Position=c(350,101,101,600,200),
                       Start=c(350,101,101,600,200),End=c(350,101,101,600,200))
    
    df1
       Chromosome Position Start End
    1:          1      350   350 350
    2:          1      101   101 101
    3:          2      101   101 101
    4:          3      600   600 600
    5:          4      200   200 200
    
    
    
        df1[,.(Chromosome,Position)][df2,
            .(Chromosome,Position=x.Position,Start,End,CpG),
           on=.(Chromosome,Position>=Start,Position<=End),nomatch=0L]
    
       Chromosome Position Start End CpG
    1:          1      101    50 200  10
    2:          1      350   300 400   2
    3:          4      200   100 200   5

我想这就是您想要的。