【问题标题】:Check if column value from one dataframe is in between (range) of two other columns of second dataframe检查一个数据帧的列值是否在第二个数据帧的其他两列之间(范围)
【发布时间】:2021-11-05 18:38:10
【问题描述】:

我有两个不同大小的数据框:

df1<-data.frame(Chr = c(1, 1,2,3,4),
                Start = c(15,120, 210,210,450),
                End = c(15,130, 210,210,450),
                Gene=c("gene1","gene2","gene3","gene3","gene3"),
                sample_id=c("ss6","ss7","ss9","ss9","ss10"))
      
  df2 <- data.frame(Chr = c(1, 1,3),
                    Start = c(10,100, 200),
                    End = c(50,200, 250),
                    Gene=c("gene1","gene2","gene3"),
                    sample_id=c("ss1","ss1","ss1"))

我想从 df1 获取 Start 并检查它是否在 df2 的 Start-End 范围之间,同时确保 Chr 相同(sample_id 不必匹配)。如果是,则理想情况下使用 df2$sample_id 向 df1 添加一列,但如果这不可能,则为 YES(或 NA 表示不匹配)。 它类似于这个问题,但我也需要匹配'Chr' Only checking range

这也类似于这个问题,我知道它应该更容易,因为我不想匹配各自的行Check if column value is in between (range) of two other column values

我试过了:

df1 %>%
  mutate(no_coverage_in = case_when(df2$Start <= Start  & df2$End >=Start & Chr == df2$Chr ~ df2$sample_id ))

但它抱怨

较长的对象长度不是较短对象长度的倍数

【问题讨论】:

  • 是的,我没有完全正确地问我的问题,所以认为最好删除和改写正确而不是浪费人们的时间
  • 您愿意接受 data.table 的答案吗? df1[df2, on=.(Chr, Start &gt;= Start, Start &lt;= End), hit := i.sample_id] 或类似的东西。
  • 基因也应该匹配?
  • 我得到:未使用的参数(on = .(Chr, Start >= Start, Start

标签: r dataframe


【解决方案1】:

我相信这会给你想要的结果:


df1 %>%
  left_join(df2 %>% rename_at(vars(Start, End, sample_id), paste0, "_2")) %>%
  mutate(sample_id_new = case_when(Start < End_2 & Start > Start_2 ~ sample_id_2)) %>% 
  select(Chr, Start, End, Gene, sample_id, sample_id_new)

输出:

  Chr Start End  Gene sample_id sample_id_new
1   1    15  15 gene1       ss6           ss1
2   1   120 130 gene2       ss7           ss1
3   2   210 210 gene3       ss9          <NA>
4   3   210 210 gene3       ss9           ss1
5   4   450 450 gene3      ss10          <NA>

【讨论】:

  • 我得到:意外令牌'>'
  • 现在试试这个。我最初有一个本地管道运算符|&gt;,如果您使用的是旧版本的 R,它可能会引发错误。让我知道它是否不起作用,因为我很感兴趣。
  • 现在可以了,谢谢。不过,我不想复制这些行 - 有一个巨大的文件。有没有不复制的方法?
  • 我现在已经修改了代码,复制是由于不匹配Gene,但我因此假设你也想匹配Gene。因此,我修改了代码。让我知道这是否是您正在寻找的答案。
  • @ Freddie J. Heather 这很好用 - 谢谢
【解决方案2】:

这是你想要的吗?

Given data frames
> df1
  Chr Start End  Gene sample_id
1   1    15  15 gene1       ss6
2   1   120 130 gene2       ss7
3   2   210 210 gene3       ss9
4   3   210 210 gene3       ss9
5   4   450 450 gene3      ss10
> df2
  Chr Start End  Gene sample_id
1   1    10  50 gene1       ss1
2   1   100 200 gene2       ss1
3   3   200 250 gene3       ss1

vec2 <- c()
for (k in 1:nrow(df1)) {
  if (df1$Chr[k] %in% df2$Chr)  {
    vec <- which(df2$Chr==df1$Chr[k])  
    for (m in 1:length(vec)) {
        if (df1$Start[k]<df2$Start[m] &df1$End[k]<df2$End[m]) {
          vec2[k] <- "Yes"
          
        }else{
          vec2[k] <- "No"
        }
    }
  }else{
    vec2[k] <- "No"
  }
}
df1$Results <- vec2

输出

> df1
  Chr Start End  Gene sample_id Results
1   1    15  15 gene1       ss6     Yes
2   1   120 130 gene2       ss7      No
3   2   210 210 gene3       ss9      No
4   3   210 210 gene3       ss9      No
5   4   450 450 gene3      ss10      No

【讨论】:

  • 这几乎可以工作...第 2 行和第 4 行也应该是“是”。我将第二个 if 语句更改为: if (df1$Start[k]>df2$Start[m] &df1$End[k])但这只是为第 2 行生成“是”
【解决方案3】:

这是一个建议。

  df1$match= sapply( 1:nrow(df1) , 
                     function(x)   
                          any(  df1[x, 'Chr']==df2[, 'Chr'] &
                                df1[x , 'Start'] <= df2[ , 'End'] & 
                                df1[x , 'Start'] >= df2[ , 'Start'] ))

【讨论】:

    【解决方案4】:

    您可以编写一个小的FUNction 来检查df1 的每一行并将其放入循环其行的lapply 中。

    FUN <- \(x, y) {
      rng <- df1[x, 2] >= y[, 2] & df1[x, 3] < y[, 3]
      chr <- df1[x, 1] == y[, 1]
      if (any(rng & chr)) df2[which(rng), 5] else NA
    }
    
    df1 <- transform(df1, match=unlist(lapply(seq.int(nrow(df1)), FUN, df2)))
    df1
    #   Chr Start End  Gene sample_id match
    # 1   1    15  15 gene1       ss6   ss1
    # 2   1   120 130 gene2       ss7   ss1
    # 3   2   210 210 gene3       ss9  <NA>
    # 4   3   210 210 gene3       ss9   ss1
    # 5   4   450 450 gene3      ss10  <NA>
    

    注意:

    我使用新的速记符号在 R>4.1.* 中创建函数。对于较旧的 R 版本,请使用 FUN &lt;- function(x, y) 或更新 R,而不是 FUN &lt;- \(x, y)

    【讨论】:

    • 我得到:意外令牌'\'
    • @zw_nz 请参阅我添加到答案中的注释。
    猜你喜欢
    • 2019-03-23
    • 2020-10-09
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    相关资源
    最近更新 更多