考虑以下数据框:

 first_name last_name
1         Al     Smith
2         Al     Jones
3       Jeff  Thompson
4      Scott  Thompson
5      Terry    Dactil
6       Pete       Zah

data <- data.frame(first_name=c("Al","Al","Jeff","Scott","Terry","Pete"),
                   last_name=c("Smith","Jones","Thompson","Thompson","Dactil","Zah"))

在此数据框中,first_name 与 last_name 的关联方式有以下三种:
  • 一对一(即 first_name 之间存在唯一关系
    和姓氏)
  • 一对多(即一个 first_name 指向多个
    last_name 值)
  • 多对一(即多个 first_name 值指向
    到一个姓氏)

  • 我希望能够快速识别三种情况中的每一种并将它们输出到数据框。因此,生成的数据帧将是:

    一对一
      first_name last_name
    1      Terry    Dactil
    2       Pete       Zah
    

    一对多
      first_name last_name
    1         Al     Smith
    2         Al     Jones
    

    多对一
       first_name last_name
    1       Jeff  Thompson
    2      Scott  Thompson
    

    我想在 dplyr 包中执行此操作。

    最佳答案

    通常,您可以使用 duplicated 函数检查值是否重复(如@RichardScriven 在对您的问题的评论中所述)。但是,默认情况下,此函数不会将多次出现的元素的第一个实例标记为重复:

    duplicated(c(1, 1, 1, 2))
    # [1] FALSE  TRUE  TRUE FALSE
    

    由于您还想处理这些情况,您通常希望在每个向量上运行 duplicated 两次,一次向前,一次向后:
    duplicated(c(1, 1, 1, 2)) | duplicated(c(1, 1, 1, 2), fromLast=TRUE)
    # [1]  TRUE  TRUE  TRUE FALSE
    

    我发现这需要大量输入,因此我将定义一个辅助函数来检查一个元素是否出现多次:
    d <- function(x) duplicated(x) | duplicated(x, fromLast=TRUE)
    

    现在你想要的逻辑都是简单的单行:
    # One to one
    data[!d(data$first_name) & !d(data$last_name),]
    #   first_name last_name
    # 5      Terry    Dactil
    # 6       Pete       Zah
    
    # One to many
    data[d(data$first_name) & !d(data$last_name),]
    #   first_name last_name
    # 1         Al     Smith
    # 2         Al     Jones
    
    # Many to one
    data[!d(data$first_name) & d(data$last_name),]
    #   first_name last_name
    # 3       Jeff  Thompson
    # 4      Scott  Thompson
    

    请注意,您也可以使用 d 函数在没有 duplicated 帮助的情况下定义 table:
    d <- function(x) table(x)[x] > 1
    

    虽然这个替代定义稍微简洁一些,但我也发现它不太可读。

    关于r - 查找列之间的一对一、一对多和多对一关系,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32828094/

    10-12 17:49