[英]R find overlap between strings in columns of two dataframes
我有以下数据框 df1 和 df2。 这些只是示例,我的真实数据框大约有 1000 行和 10 列。
df1 = data.frame(V1 = c(1,2), V2 = c("a, b, d", "c, g"))
> df1
V1 V2
1 1 a, b, d
2 2 c, g
df2 = data.frame(V3 = c(1,2,3), V4 = c("a, c", "b, e", "a, g"))
> df2
V3 V4
1 1 a, c
2 2 b, e
3 3 a, g
如您所见,列 V2 和 V4 包含由", "
分隔的值。
我现在想逐行遍历我的 df1 并检查 V2 中存在的任何值是否与 V4 中存在的值之一匹配。 所以我不想比较完整的列内容,而是比较每个值的值。
这就是我的 output df3 的样子
df3 = data.frame(V1 = c(1, 1, 1, 2, 2), V2 = c("a, b, d", "a, b, d", "a, b, d", "c, g", "c, g"), V5 = c("a","a","b","c","g"), V3 = c(1, 3, 2, 1, 3), V4 = c("a, c","a, g", "b, e", "a, c", "a, g"), V6 = c("a", "a","b", "c", "g"))
> df3
V1 V2 V5 V3 V4 V6
1 1 a, b, d a 1 a, c a
2 1 a, b, d a 3 a, g a
3 1 a, b, d b 2 b, e b
4 2 c, g c 1 a, c c
5 2 c, g g 3 a, g g
让我们看一下df1的第一行。 在 V2 中有值“a”、“b”和“d”。 我们从“a”开始,如果“a”出现在 V4 中,则查看 df2。 df2 的第 1 行和第 3 行也是如此。 我们在 output df3 中创建了两行。 第 1 行包含第一个匹配的信息:原始列 V1、V2、V3 和 V4 + 2 个新列 V5 和 V6,它们分别包含来自 df1 和 df2 的匹配值“a”。
我希望这很清楚。
我将从一个 for 循环开始,我认为可能有必要将我的列 V2 拆分为“,”,但我不确定是否需要这样做。
for (row in 1:nrow(df1)) {
// split col V2 of df1 by ','
// if V2 %in% in df2$V4 ...
}
使用separate_rows
分隔df1
和df2
上的折叠列,并将它们与inner_join
连接在一起。
library(dplyr)
library(tidyr)
df.a <- df1 %>%
mutate(V5 = V2) %>%
separate_rows(V5)
df.b <- df2 %>%
mutate(V6 = V4) %>%
separate_rows(V6)
inner_join(df.a, df.b, c("V5" = "V6"))
# V1 V2 V5 V3 V4
# 1 1 a, b, d a 1 a, c
# 2 1 a, b, d a 3 a, g
# 3 1 a, b, d b 2 b, e
# 4 2 c, g c 1 a, c
# 5 2 c, g g 3 a, g
这是使用merge
+ strsplit
的基本 R 解决方案
df3 <- within(merge(df1,df2),
V5 <- unlist(Map(function(x,y) ifelse(length(u <- intersect(x,y)),u,NA),
strsplit(as.character(V2),", "),
strsplit(as.character(V4),", "))))
df3 <- (df3 <- subset(df3,complete.cases(df3)))[order(df3$V1),]
这样
> df3
V1 V2 V3 V4 V5
1 1 a, b, d 1 a, c a
3 1 a, b, d 2 b, e b
5 1 a, b, d 3 a, g a
2 2 c, g 1 a, c c
6 2 c, g 3 a, g g
这是另一个转换为 long 然后进行合并的解决方案,现在使用 data.table
## Convert to data.table with character columns (rather than factor)
library(data.table)
setDT(df1)[, V2 := as.character(V2)]
setDT(df2)[, V4 := as.character(V4)]
## Find common elements
common <-
merge(
df1[, .(V5 = strsplit(V2, ', ')[[1]]), V1],
df2[, .(V5 = strsplit(V4, ', ')[[1]]), V3])
common
# V5 V1 V3
# 1: a 1 1
# 2: a 1 3
# 3: b 1 2
# 4: c 2 1
# 5: g 2 3
## Merge back to original data
merge(merge(common, df1, by = 'V1'), df2, by = 'V3')
# V3 V1 V5 V2 V4
# 1: 1 1 a a, b, d a, c
# 2: 1 2 c c, g a, c
# 3: 2 1 b a, b, d b, e
# 4: 3 1 a a, b, d a, g
# 5: 3 2 g c, g a, g
最后一步也可以写成reduce
,而不是多次显式调用merge
## Merge back to original data
purrr::reduce2(list(df1, df2), c('V1', 'V3'), merge, .init = common)
# V3 V1 V5 V2 V4
# 1: 1 1 a a, b, d a, c
# 2: 1 2 c c, g a, c
# 3: 2 1 b a, b, d b, e
# 4: 3 1 a a, b, d a, g
# 5: 3 2 g c, g a, g
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.