如何在使用 R 中的条件删除两个数据框中的重复行后在两个数据框中找到相互对

How to find mutual pairs in two data frames after removing duplicate rows in both using a condition in R

我的数据是这样的:

RES1 <- c("A","B","A","A","B")
RES2 <- c("B","A","A","B","A")
VAL1 <-c(3,5,3,6,8)
VAL2 <- c(5,3,7,2,7)
dff <- data.frame(RES1,VAL1,RES2,VAL2)
dff
  RES1 VAL1 RES2 VAL2
  1    A    3    B    5 
  2    B    5    A    3
  3    A    3    A    7
  4    A    6    B    2
  5    B    8    A    7

我想删除我已经拥有相同 res1-res2 对的行。例如:A 3 与B 5 交互。这就是我想要的信息。我不在乎哪一对是第一对。 B 5 与 A 3 或 A 3 与 B 5。我想要得到的是以下数据框:

output
  RES1 VAL1 RES2 VAL2
   1    A    3    B    5
   2    A    3    A    7
   3    A    6    B    2
   4    B    8    A    7

然后我想对另一个数据框做同样的事情,例如:

RES3 <- c("B","B","B","A","B")
RES4 <- c("A","A","A","A","B")
VAL4 <- c(3,7,5,3,8)
VAL3 <- c(5,8,3,7,3)
df2 <- data.frame(RES3,VAL3,RES4,VAL4)

df2
  RES3 VAL3 RES4 VAL4
   1     B     5     A     3
   2     B     8     A     7
   3     B     3     A     5
   4     A     7     A     3
   5     B     3     B     8

最后,我只想保留相互对(在我的定义中,两对是相同的,保留一对是必不可少的:"A 5" - "B 3" 与 "B 3" - "A 5"。换句话说,顺序无关紧要。

我希望的最终输出应该有以下对,它们是唯一的并且存在于两个数据帧中:

mutualpairs
  RESA VALA RESB VALB
  A     3     B     5
  A     3     A     7
  B     8     A     7

使用我中的逻辑,你可以试试这个

df2 <- structure(list(RES3 = c("B", "B", "B", "A", "B"), VAL3 = c(5, 8, 3, 7, 3), RES4 = c("A", "A", "A", "A", "B"), VAL4 = c(3, 7, 5, 3, 8)), .Names = c("RES3", "VAL3", "RES4", "VAL4"), row.names = c(NA, -5L), class = "data.frame")
dff <- structure(list(RES1 = c("A", "B", "A", "A", "B"), VAL1 = c(3, 5, 3, 6, 8), RES2 = c("B", "A", "A", "B", "A"), VAL2 = c(5, 3, 7, 2, 7)), .Names = c("RES1", "VAL1", "RES2", "VAL2"), row.names = c(NA, -5L), class = "data.frame")

编写一个函数,将数据框拆分成列对并对交互对进行排序

f <- function(data) {
  idx <- t(apply(sapply(seq(ncol(data) / 2), function(x)
    interaction(data[, 2 * x + -1:0], sep = ' ')), 1, sort))
  apply(idx, 1, paste, collapse = ' ')
}

例如,

f(dff)
# [1] "A 3 B 5" "A 3 B 5" "A 3 A 7" "A 6 B 2" "A 7 B 8"

在两个数据框上使用它并找出共同点;那么您可以使用此索引来 1) 对原始数据帧进行子集化或 2) 因为这已经包含您想要的信息,只需撤消 f 所做的操作,例如

dff$idx <- f(dff)
df2$idx <- f(df2)

idx <- intersect(dff$idx, df2$idx)

read.table(text = idx, col.names = c('RESA','VALA','RESB','VALB'))
#   RESA VALA RESB VALB
# 1    A    3    B    5
# 2    A    3    A    7
# 3    A    7    B    8

这是一种解决方案:

library(dplyr)
df1$combined <- apply(df1, 1, function(x) paste(sort(c(paste(x[1], x[2], collapse = ','), paste(x[3], x[4], collapse = ','))), collapse = ','))
df2$combined <- apply(df2, 1, function(x) paste(sort(c(paste(x[1], x[2], collapse = ','), paste(x[3], x[4], collapse = ','))), collapse = ','))

df <- inner_join(df1 %>% group_by(combined) %>% slice(1), df2 %>% group_by(combined) %>% slice(1))
df <- df %>% ungroup() %>% select(RES1, VAL1, RES2, VAL2)

给你这个输出:

Source: local data frame [3 x 4]

    RES1  VAL1   RES2  VAL2
  (fctr) (dbl) (fctr) (dbl)
1      A     3      A     7
2      A     3      B     5
3      B     8      A     7

这种方法仅通过上述 apply 函数中的数据并依赖于高效的 dplyr group_byinner_join.

主要任务是按特定顺序获取成对的列,以便按顺序对它们进行分组。前两行只是将两对列 'appended' 放入一个有序的字符串中,因此出现在每一对中的值都被视为相同。然后,group_by() 将所有具有相同 combined 列的行分组并获取第一行(使用 slice)。使用 inner_join 连接生成的两个数据帧可确保仅保留两个数据帧之间共有的行。最后一行只是选择要保留的所需列。顺便说一句 - 关于上面的消息,如果您只想通过 combined 列而不是其他任何方式加入,您可能需要在 inner_join 调用中指定 by 参数。