在列之间找到一对一,一对多和多对一的关系

glo*_*onn 3 r dplyr

请考虑以下数据框:

 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"))
Run Code Online (Sandbox Code Playgroud)

在此数据框中,first_name与last_name相关的方式有三种:

  • 一对一(即first_name和last_name之间存在唯一关系)
  • 一对多(即一个first_name指向多个last_name值)
  • 多对一(即多个first_name值指向一个last_name)

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

一对一

  first_name last_name
1      Terry    Dactil
2       Pete       Zah
Run Code Online (Sandbox Code Playgroud)

一对多

  first_name last_name
1         Al     Smith
2         Al     Jones
Run Code Online (Sandbox Code Playgroud)

多对一

   first_name last_name
1       Jeff  Thompson
2      Scott  Thompson
Run Code Online (Sandbox Code Playgroud)

我想在dplyr包中做到这一点.

jos*_*ber 6

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

duplicated(c(1, 1, 1, 2))
# [1] FALSE  TRUE  TRUE FALSE
Run Code Online (Sandbox Code Playgroud)

由于您还想要获取这些情况,您通常希望duplicated在每个向量上运行两次,一次向前运行,一次向后运行:

duplicated(c(1, 1, 1, 2)) | duplicated(c(1, 1, 1, 2), fromLast=TRUE)
# [1]  TRUE  TRUE  TRUE FALSE
Run Code Online (Sandbox Code Playgroud)

我发现这是一个很多的输入,所以我将定义一个辅助函数,检查一个元素是否出现多次:

d <- function(x) duplicated(x) | duplicated(x, fromLast=TRUE)
Run Code Online (Sandbox Code Playgroud)

现在你想要的逻辑是简单的单行:

# 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
Run Code Online (Sandbox Code Playgroud)

请注意,您也可以在d没有duplicated使用table函数的帮助下进行定义:

d <- function(x) table(x)[x] > 1
Run Code Online (Sandbox Code Playgroud)

虽然这个替代定义稍微简洁一些,但我发现它的可读性较差.

  • 我现在希望我的名字是Terry Dactil (5认同)