从一个数据框的多个列中查找不在另一个数据框的多个列中的元素

时间:2017-11-07 04:30:42

标签: r tidyverse

library(tidyverse) 

我有两个数据帧(参见底部的示例代码),名为Df1和Df2。我想找到Df1中的电话号码(来自所有列),这些电话号码不在Df2的任何电话号码列中。

首先,我重构Df1,以便每行只有一个Id。

Df1<-Df1 %>% 
gather(key, value, -Id) %>%
filter(!is.na(value)) %>% 
select(-key) %>% 
group_by(Id) %>% 
filter(!duplicated(value)) %>% 
mutate(Phone=paste0("Phone_",1:n())) %>% 
spread(Phone, value)

接下来,我重命名Df2然后使用连接来仅查找Df1中Df2中的ID。

Df2<-Df2%>%set_names(c("Id","Ph1","Ph2"))
DfJoin<-left_join(Df2,Df1,by="Id")

这就是我被困的地方。我想找到Df1(Phone1 Phone2和Phone3)中不在Df2(Ph1和Ph2)中的所有数字。以下是代码的一些想法。我尝试了很多这种想法的变化,但找不到实现我想要的方法。最终产品应该只是一个表格,其中任何Df1列中的电话号码都不在任何Df2列中以及相关的Id。我还想知道是否有另一个连接或设置操作可以更有效地实现这一目标?

 DfJoin<-DfJoin%>%mutate(New=if_else(! DfJoin[2:3] %in% DfJoin[4:6]),1,0)

 DfJoin<-DfJoin%>%filter(! DfJoin[2:3] %in% DfJoin[2:4])

示例数据:

Dataframe 1:

Id<-c(199,148,148,145,177,165,144,121,188,188,188,111)
Ph1<-c(6532881717,6572231223,6541132112,6457886543,6548887777,7372222222,6451123425,6783450101,7890986543,6785554444,8764443344,6453348736)
Ph2<-c(NA,NA,NA,NA,NA,7372222222,NA,NA,NA,6785554444,NA,NA)

Df1<-data.frame(Id,Ph1,Ph2)

Dataframe 2:

Id2<-c(199,148,142,145,177,165,144,121,182,109,188,111)
Phone1<-c(6532881717,6572231223,6541132112,6457886543,6548887777,7372222222,6451123425,6783450101,7890986543,6785554400,8764443344,6453348736)
 Phone2<-c(NA,NA,NA,NA,NA,7372222222,NA,NA,NA,6785554444,NA,NA)

 Df2<-data.frame(Id2,Phone1,Phone2)

2 个答案:

答案 0 :(得分:0)

您是否尝试过anti_join(a, b, by = "x1")

这基本上为您提供了不在b

中的所有行
DfJoin <- anti_join(Df1, Df2, by = "Id")

tidyr_dplyr cheatsheet

使用上面的备忘单进行tidyverse中的数据操作

答案 1 :(得分:0)

考虑这个问题的一种方法:

  1. 每个ID号在df1都有一组电话号码。
  2. 每个ID号在df2都有一组电话号码。
  3. 您希望在每个ID中找到df1df2之间的set difference
  4. 您可以通过将基本R函数setdiff()映射到已连接的数据帧来完成此操作。为此,您需要将数据帧转换为列表列格式,其中每个ID的所有电话号码都作为列表存在于数据帧的“单元格”中。这可以通过合并group_by()summarize()list()轻松完成。

    # create example data
    Id <- c(199,148,148,145,177,165,144,121,188,188,188,111)
    ph1 <- c(6532881717,6572231223,6541132112,6457886543,6548887777,7372222222,6451123425,6783450101,7890986543,6785554444,8764443344,6453348736)
    ph2 <- c(NA,NA,NA,NA,NA,7372222222,NA,NA,NA,6785554444,NA,NA)
    
    df1 <- data.frame(Id, ph1, ph2)
    
    Id2 <- c(199,148,142,145,177,165,144,121,182,109,188,111)
    phone1 <- c(6532881717,6572231223,6541132112,6457886543,6548887777,7372222222,6451123425,6783450101,7890986543,6785554400,8764443344,6453348736)
    phone2 <- c(NA,NA,NA,NA,NA,7372222222,NA,NA,NA,6785554444,NA,NA)
    
    df2 <- data.frame(Id=Id2, phone1, phone2)
    
    
    # convert the data to list-column format
    df1.listcol <- df1 %>%
        gather(col, phone, -Id) %>%
        na.omit() %>%
        group_by(Id) %>%
        summarize(phone_list1 = list(phone)) 
    
    df2.listcol <- df2 %>%
        gather(col, phone, -Id) %>%
        na.omit() %>%
        group_by(Id) %>%
        summarize(phone_list2 = list(phone)) 
    

    请查看这些数据框,以确保您了解我们如何重新格式化它们。显然,我们可以通过将此转换过程转换为函数来保存几行代码,然后在df1df2中调用函数,但我没有在此处执行此操作。

    # join the two listcol dfs by Id, then map setdiff on the two columns
    result <- 
        df1.listcol %>%
        left_join(df2.listcol, by='Id') %>%
        mutate(only_list_1 = map2(phone_list1, phone_list2, ~setdiff(.x, .y))) %>%
        select(Id, only_list_1) %>%
        unnest()
    
    result
    

    result

    Id  only_list_1
    148 6541132112
    188 7890986543
    188 6785554444