r - 如何基于字符串匹配合并(加入)数据框?

标签 r string merge tidyverse character

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"))

screenshot of goal dataframe

在伪代码中,这是我想做的:

  1. 在 df1 中创建一个名为“匹配”的新列,其中将包含有关 df1 和 df2 之间是否存在 df1 中任何给定行的匹配的信息

  2. 比较 df1$Name 和 df2$Symbol,如果它们相同,则用 df2$Symbol 填充 df1$match

  3. 如果它们不相同,则在 df2$Synonym 列中查找完全匹配,如果找到,则将相应的 df2$Symbol 分配给 df1$match

  4. 根据 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/

相关文章:

mysql - 从 Shiny 的 renderUI 中获取

R:读取 .csv 将所有 ""(空格)变为 NA

python - 在 Python 中使用 str.replace() 删除函数包装

json - 将数组映射到没有公共(public)字段的对象

SQL Server 2008 MERGE 语句 - 如何禁用 INSTEAD OF INSERT 触发器以允许 MERGE

r - 如何将数据帧列表取消列出到 R 中的单个数据帧中

python - 将图表重新绘制为视频

java - 检查java中包含空格的字符串的排列

string - 如何从 Mac 中的二进制文件中提取硬编码字符串?

xml - 从命令行合并多个 XML 文件