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