繁体   English   中英

R 在两个数据帧的列中找到字符串之间的重叠

[英]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分隔df1df2上的折叠列,并将它们与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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM