【问题标题】:Join data but ignore missing values连接数据但忽略缺失值
【发布时间】:2019-03-29 18:52:42
【问题描述】:

我在使用 dplyr 连接数据帧时遇到了一些问题,我想忽略 NA。

我拥有的数据很大,但简化版本如下:

id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)

df <- data.frame(A, B, C)

     id    A    B    C
1    id1   E    T    NA
2    id2   F    NA   T
3    id3   G    N    U
4    id4   NA   T    NA

我有一个想与 df 匹配的条目,例如:

df2 <- data.frame(A = "E", B = "T", C = "M")

    A    B    C
1   E    T    M

因此,我想从 df 中获取与 df2 匹配的所有行,但应该忽略 NA。所以结果应该是这样的:

     id    A    B    C
1    id1   E    T    NA
2    id4   NA   T    NA

我试图用 semi_join 来做这件事,但到目前为止没有用:

result <- df %>%
  group_by(n = seq(n())) %>%
  do(modify_if(., is.na, ~NULL) %>%
       semi_join(df2, by = c("A", "B", "C"))) %>%
  ungroup %>%
  select(-n)

结果:

Error: `by` can't contain join column `C` which is missing from LHS
Call `rlang::last_error()` to see a backtrace

谁知道答案?

【问题讨论】:

  • 你能解释一下你想要的结果吗?为什么行E T NANA T NA会被返回?
  • df2 中的 B 应该是“T”而不是“M”吗?
  • 正如其他人所说,您的示例看起来有点混乱。在任何情况下,semi_join 都不是答案,因为它与其他 dplyr 加入工作的方式相同。您可能只想制作每个组合(笛卡尔积),然后过滤至少一对列或没有不匹配的列。
  • @thc 你是对的,对不起
  • @svenhalvorson 抱歉,我不明白您的意思,您能否提供链接或更多信息?

标签: r dplyr na semi-join


【解决方案1】:

这是一个混合了 tidyverse 和 base R 的解决方案。我认为这很清楚,但我会对不完全人为的纯 tidyverse 实现感兴趣。

这个想法是首先展开dfdf2 中的所有条目,然后使用循环过滤所有列。

数据:

id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)

df <- data.frame(id, A, B, C, stringsAsFactors = F) # Make sure to use strings not factors
df2 <- data.frame(A = "E", B = "T", C = "M", stringsAsFactors = F)

代码:

library(tidyr)
results <- crossing(df, df2)
select_columns <- c("A", "B", "C")
for(col in select_columns) {
  keep <- is.na(results[[col]]) | results[[col]] == results[[paste0(col, 1)]]
  results <- results[keep,, drop=F]
}
results <- results %>% dplyr::select(id, A:C) %>% distinct
results

   id    A B    C
1 id1    E T <NA>
2 id4 <NA> T <NA>

【讨论】:

    【解决方案2】:

    如果您只需要对一组值执行此操作,这可能是最直接的方法:

    d[A %in% c("E",NA) & B %in%c("T",NA) & C %in% c("M",NA),]
    

    【讨论】:

      【解决方案3】:

      另一个使用 tidyverse 和 base (dplyr, tidyr, base) 的例子:

      在此我将您的 df2 转换为一个数据框,其中包含您想要接受的所有值组合( (E or NA) & (T or NA) & (M or NA) ),然后我对此进行内部连接全套。还有其他方法可以创建所有可能组合的数据框,但这个使用 tidyr 相当容易。

      library(dplyr)
      library(tidyr)
      
      id <- c("id1", "id2", "id3", "id4")
      A <- c("E", "F", "G", NA)
      B <- c("T", NA, "N", "T")
      C <- c(NA, "T", "U", NA)
      
      df <- data.frame(A, B, C, stringsAsFactors = FALSE)
      
      df2 <- data.frame(A = "E", B = "T", C = "M",stringsAsFactors = FALSE)
      
      df2_expanded <- df2 %>%
        rowwise() %>%
        mutate(combinations = list(expand.grid(A = c(A,NA),B = c(B,NA),C = c(C,NA),stringsAsFactors = FALSE))) %>%
        select(-A,-B,-C) %>%
        unnest(combinations)
      
      # A tibble: 8 x 3
      #   A     B     C    
      # <chr> <chr> <chr>
      # 1 E     T     M    
      # 2 NA    T     M    
      # 3 E     NA    M    
      # 4 NA    NA    M    
      # 5 E     T     NA   
      # 6 NA    T     NA   
      # 7 E     NA    NA   
      # 8 NA    NA    NA   
      
      df %>%
        inner_join(df2_expanded)
      
      #      A B    C
      # 1    E T <NA>
      # 2 <NA> T <NA>
      

      【讨论】:

        猜你喜欢
        • 2020-08-11
        • 1970-01-01
        • 2017-06-20
        • 2020-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多