【问题标题】:How to find matches for a row in a dataframe conditional on many rows from another dataframe如何根据来自另一个数据帧的许多行来查找数据帧中的一行的匹配项
【发布时间】:2019-11-27 14:03:22
【问题描述】:

我正在尝试编写一个函数,该函数遍历一个数据库的每一行,并将此数据帧中的值与另一个数据帧中所有行的值进行比较,并找出哪些行匹配/不匹配。我认为一个例子会更好地解释:

数据框 1

chr pos
1 150
1 225
2 150 
3 600 

数据框 2

chr start stop 
1 100 200
1 250 300
2 100 300
3 50 150 
3 500 700 

期望的输出

chr pos 
1 225

这个想法是对 df1 中的每一行逐一评估 df2 中的每一行。在每次评估中,chr 必须完全匹配,然后来自 df1 的 pos 值必须落在 df2 中每个给定行的起始停止值的范围之外。我很欣赏这是一个冗长的问题,但本质上我想要一种方法来查找 df1 中的哪些行不适合 df2 中的任何范围。

【问题讨论】:

    标签: r


    【解决方案1】:

    由于您正在查看要与 df2 范围进行比较的 df1 值,因此我将首先执行 left_join。因此,很容易检查 pos 是否超出范围(即小于 start 或大于 stop)

    df1 <- data.frame(chr = c(1,1,2,3), pos = c(150, 225, 150, 600))
    df2 <- data.frame(chr = c(1,1,2,3,3), start = c(100, 250, 100, 50, 500), stop = c(200, 300, 300, 150, 700))
    
    df1 %>% 
      left_join(df2, by = c("chr")) %>% 
      filter(pos < start | pos > stop) %>% 
      select(chr, pos)
    

    【讨论】:

    • 执行 left_join 将乘以匹配染色体的行,所以我仍然会得到每一行被正确评估的结果吗?我不敢相信我没有想到这么简单的解决方案,所以谢谢。
    【解决方案2】:

    您可以使用sapply 遍历df1 的所有行并测试它们是否适合df2。生成的索引可用于替换那些不适合df2df1

    df1[unlist(sapply(seq_len(nrow(df1)), function(i) {
      idx  <- df1$chr[i] == df2$chr
      if(!any(df1$pos[i] >= df2$start[idx] & df1$pos[i] <= df2$stop[idx])) i else NULL
    })),]
    #  chr pos
    #2   1 225
    

    或者你使用findInterval

    do.call(rbind, sapply(unique(df1$chr), function(i) {
      idx1 <- df1$chr == i
      idx2 <- df2$chr == i
      ii  <- findInterval(df1$pos[idx1], c(t(df2[idx2, c("start", "stop")]))) %% 2 == 0
      if(any(ii)) {df1[idx1,][ii,]
      } else {NULL}
    }))
    #  chr pos
    #2   1 225
    

    【讨论】:

      【解决方案3】:

      这是在data.table 中使用非等值反连接的选项:

      df1[!df2, on=.(chr, pos>start, pos<stop)]
      

      输出:

         chr pos
      1:   1 225
      

      数据:

      library(data.table)
      df1 <- fread("chr pos
      1 150
      1 225
      2 150 
      3 600")
      df2 <- fread("chr start stop 
      1 100 200
      1 250 300
      2 100 300
      3 50 150 
      3 500 700")
      

      【讨论】:

        猜你喜欢
        • 2019-08-14
        • 2021-01-26
        • 2015-10-19
        • 2019-08-20
        • 2018-11-05
        • 1970-01-01
        • 2015-12-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多