TL;DR:我想根据包含标识符的多个同义词的列合并两个数据框。
这是我向 stackoverflow 提出的第一个问题,但我已经被这个看似简单的问题困扰了太久,所以我将非常感谢任何帮助!
我有两个数据框,它们都包含一个或多个描述一行的字符列。我想合并这些数据框,虽然有时它们有直接匹配,但没有单个标识符列,而是可以匹配的多个同义词。
这是两个数据框的简单可重现示例:
df1 <- data.frame("Name" = c("a", "b", "c"))
df2 <- data.frame("Symbol" = c("a", "two", "d"),
"Synonym" = c("", "b | 2", "c-four"))
我希望第一行直接匹配(“a”),第二行匹配同义词(“b”),第三行不匹配(“c”)。 (不匹配的行(“d”)可能包含也可能不包含在输出中。)
这是我希望作为合并输出的数据框:
goal_df <- data.frame("Name" = c("a", "b", "c", NA),
"Symbol" = c("a", "two", NA, "d"),
"Synonym" = c("", "b | 2", NA, "c-four"))
在伪代码中,这是我想做的:
在 df1 中创建一个名为“匹配”的新列,其中将包含有关 df1 和 df2 之间是否存在 df1 中任何给定行的匹配的信息
比较 df1$Name 和 df2$Symbol,如果它们相同,则用 df2$Symbol 填充 df1$match
如果它们不相同,则在 df2$Synonym 列中查找完全匹配,如果找到,则将相应的 df2$Symbol 分配给 df1$match
根据 df1$match 和 df2$Symbol 合并两个数据帧
这是我到目前为止尝试过的(一些事情):
首先,我将每个同义词的同义词拆分为单独的字符串,以便进行精确比较(这会创建一个列表类型,因为每行可以有多个同义词):
df2 <- df2 %>%
mutate(syns = strsplit(df2$Synonym, split = "|", fixed = T))
df3 <- df1 %>% mutate(
match = case_when(
Name %in% df2$Symbol ~ Name,
Name %in% df2$syns ~ df2$Symbol, #this line
TRUE ~ NA_character_)) %>%
left_join(df2, by = c("match" = "Symbol"), all.x = T)
不幸的是,我猜这一行由于多种原因无法正确计算。
我为这一行尝试过的替代方案:
sapply(Name, grep, df2$syns) ~ df2$Symbol, #this line
sapply(paste0("\\b", Name, "\\b"), grep, df2$syns) ~ df2$Symbol, #this line
但是,我收到以下错误:
Error in `mutate()`:
! Problem while computing `match = case_when(...)`.
Caused by error in `case_when()`:
! LHS of case 2 (`sapply(Name, grep, df2$syns)`) must be
a logical vector, not a list.
Run `rlang::last_error()` to see where the error occurred.
也许首先 strsplit Synonym 列是错误的方法?我不确定 1) 如何只匹配完全匹配(例如它不匹配“c”和“c-four”)和 2)一旦我成功比较了字符串,如何合并两个数据帧(因为在 case_when 中似乎无法从不同的数据帧分配值。
我希望我能彻底描述我的问题!提前感谢您提供的任何帮助。我觉得自己被困在这个看似简单的任务中很可笑。
最佳答案
也许这使用 fuzzyjoin
:
(也可以使用 %>%
代替 |>
。)
library(tidyverse)
library(fuzzyjoin)
df1 <- data.frame("Name" = c("a", "b", "c"))
df2 <- data.frame("Symbol" = c("a", "two", "d"),
"Synonym" = c("", "b | 2", "c-four"))
df2_regex <- df2 |>
mutate(regex = str_c(Symbol, Synonym, sep = "|") |>
str_remove_all(" ") |>
str_remove("\\|$") |>
str_replace_all("\\|", "$\\|^"),
regex = str_c("^", regex, "$")
)
df1 |>
regex_full_join(df2_regex, by = c(Name = "regex")) |>
select(-regex)
#> Name Symbol Synonym
#> 1 a a
#> 2 b two b | 2
#> 3 c <NA> <NA>
#> 4 <NA> d c-four
由 reprex package 创建于 2022-06-06 (v2.0.1)
关于r - 如何基于字符串匹配合并(加入)数据框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72519502/