选择成对重复的行[A-B和B-A]

4

我有一个输入矩阵

df <- data.frame(a = c(1,1,2,4,3,5,2,1,1,3), b = c(4,3,3,1,2,2,4,4,4,2), d = LETTERS[1:10])

我想要得到

out <- data.frame(a = c(1,2,4,3,1,1,3), b = c(4,3,1,2,4,4,2), d = c(A,C,D,E,H,I,J))

#   a b d
# 1 1 4 A
# 2 2 3 C
# 3 4 1 D
# 4 3 2 E
# 5 1 4 H
# 6 1 4 I
# 7 3 2 J

我希望提取两列中重复的行,且顺序可以颠倒。

我尝试了df[duplicated(df[c("a")]) | duplicated(df[c("b")]) ,]但它并没有起作用。

有什么建议吗?


1
我不确定这是否是重复的,但它非常接近其他几个问题。与更常见的情况唯一的区别在于您想保留非唯一行而不是删除它们,这只是一个否定的问题。例如:从数据框中提取唯一组合行或对成对重复值进行删除等问题。还有其他类似的问题。 - Jota
3个回答

2

您可以通过按行排序的列 ab 来对数据框进行分组,使用列 abpminpmax,然后根据组中至少包含两行的条件进行过滤:

library(dplyr)
df %>% 
       group_by(pmin(a,b), pmax(a,b)) %>% 
       filter(n() >= 2) %>% 
       ungroup() %>% 
       select(a,b,d)

# Source: local data frame [7 x 3]
# 
#       a     b      d
#   <dbl> <dbl> <fctr>
# 1     1     4      A
# 2     2     3      C
# 3     4     1      D
# 4     3     2      E
# 5     1     4      H
# 6     1     4      I
# 7     3     2      J

1
一个基于R的等效方法(或者至少是相似的方法)可能是 dfDups <- with(df, cbind(pmin(a,b), pmax(a,b))); df[duplicated(dfDups) | duplicated(dfDups, fromLast = TRUE), ] - Jota

1
在基本的R语言中,您可以使用duplicatedapply函数来实现此功能:
df[(duplicated(df$a)&duplicated(df$b))|
   apply(df,1, function(l) sum((l[["a"]]==df$b)&(l[["b"]]==df$a))>0),]

   a b d
1  1 4 A
3  2 3 C
4  4 1 D
5  3 2 E
7  2 4 G
8  1 4 H
9  1 4 I
10 3 2 J

“base R”(也就是您的解决方案)似乎更快!!!使用提供的数据进行微基准测试,表明您的解决方案比“dplyr”解决方案快近4倍。 - Joseph Wood

0

我们也可以使用成对的最大值和最小值(pmax和pmin)来覆盖顺序,然后从第一个和最后一个找到重复行,并合并两个结果。虽然这是一种较长的解决方案,但可能会引起兴趣:

df <- data.frame(a = c(1,1,2,4,3,5,2,1,1,3), b = c(4,3,3,1,2,2,4,4,4,2), d = LETTERS[1:10])

out <- data.frame(a = c(1,2,4,3,1,1,3), b = c(4,3,1,2,4,4,2), d = c('A','C','D','E','H','I','J'))    


mx<- with (df, pmax(a,b))
mn<- with (df, pmin(a,b))

df2<- data.frame(mx, mn)
df2

a<- df[duplicated(df2),]
b<- df[duplicated(df2,fromLast = T),]

res<- merge(a,b,all = T)
res<- res[order(res$d),]

res 
out

#check
sum (as.character(res$d) !=as.character(out$d) )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接