【问题标题】:How to fuzzy match by words (not letters) in R?如何在 R 中通过单词(不是字母)进行模糊匹配?
【发布时间】:2021-04-01 15:04:03
【问题描述】:

我需要基于包含不完全匹配的名称的列合并两个数据集,有时是因为其中一列相对于另一列缺少名称。例如,在一列中我有"Martín Gallardo",而在另一列中我有"Martín Ricardo Gallardo"。另一个问题是,在某些名字和姓氏中出现颠倒,例如"Martín Gallardo" 在一个和"Gallardo Martín" 在另一个。如何使用 R 匹配这个?我的第一个想法是在两者中都使用str_split,并将一个集合上的每个分配给与另一个集合中更多元素匹配的那个,但我不知道如何编码。

谢谢。

编辑:数据看起来像这样

A <- tibble(email=c("martingallardo23@gmail.com","raulgimenez@gmail.com"), 
name=c("martin", "raul"), last_name=c("gallardo","gimenez"), 
full_name=c("martin gallardo", "raul gimenez"))
A
#  A tibble: 2 x 4
#   email                      name   last_name full_name
#   <chr>                      <chr>  <chr>     <chr>          
# 1 martingallardo23@gmail.com martin gallardo  martin gallardo
# 2 raulgimenez@gmail.com      raul   gimenez   raul gimenez   

B <- tibble(email=c("martingallardo@gmail.com", "raulgimenez2@gmail.com"), 
name=c("martin ricardo", "gimenez"), last_name=c("gallardo", "raul"), 
full_name=c("martin ricardo gallardo", "gimenez raul"), other_data=c("A", "B"))
B
# A tibble: 2 x 5
#   email                    name           last_name full_name              other_data
#   <chr>                    <chr>          <chr>     <chr>                   <chr>     
# 1 martingallardo@gmail.com martin ricardo gallardo  martin ricardo gallardo A         
# 2 raulgimenez2@gmail.com   gimenez        raul      gimenez raul            B   

【问题讨论】:

  • 您能分享一段可重现的数据吗?以便其他人可以更有效地帮助您。
  • @AnoushiravanR 我添加了一个数据示例,这行得通吗?我想使用 full_name 将 A 与 B 匹配。还有一个可用的电子邮件,但并不总是匹配。
  • @MartinGallardo 然后你想合并 2 个数据集?我的意思是基于那些匹配的行。
  • @AnoushiravanR 是的,完全正确。
  • @PKumar 我会试试的。谢谢。

标签: r string-matching stringr fuzzyjoin


【解决方案1】:

这是一种 tidyverse 方法来进行连接。它基本上从 B 中找到与 A 的常用词数量最多的 full_name。 图书馆(tidyverse)

A1 <- tibble(
  nombre_completo = c("martin gallardo", "raul gimenez")
  ) %>%
  mutate(
    id_A = row_number()
  )

B1 <- tibble(
  nombre_completo=c("martin ricardo gallardo", "gimenez raul"),
  other_data=c("A", "B")
  ) %>%
  mutate(
    id_B = row_number()
  )


A2 <- A1 %>%
  mutate(
    name_words = str_split(nombre_completo, pattern = " ")
  ) %>%
  unnest(cols = c(name_words))

B2 <- B1 %>%
  mutate(
    name_words = str_split(nombre_completo, pattern = " ")
  ) %>%
  unnest(cols = c(name_words)) %>%
  select(name_words, id_B )


left_join(A2, B2, by = "name_words") %>%
  group_by(nombre_completo, id_A, id_B) %>%
  count() %>% ungroup() %>%
  group_by(nombre_completo, id_A) %>%
  slice_max(order_by = n) %>%
  select("nombre_completo_A" = nombre_completo, id_A, id_B) %>%
  left_join(B1, by = "id_B")

【讨论】:

  • 这很好,非常感谢。有没有办法最终只得到最合适的?我得到一个 nombre_completo_A 与来自 nombre_completo 的几个匹配,所有这些都至少共享一个单词。再次感谢您!
  • 其实我想我明白了。谢谢!
  • 不客气。请随意投票/将答案标记为已接受。
  • 好主意,亲爱的@Jakub.Novotny,你当然值得一票。
【解决方案2】:

为了匹配这两个数据集,我首先在数据集A 的重组形式中创建了一个列nombre_completo2,基于数据集A 中的nombre_completo 如何部分匹配数据中的同一列设置B。然后我合并了这两个数据集,以便将数据集B 中的附加列添加到A 的重组形式中。这就是我首先解释您想要的输出的方式,所以我希望它对您有用:

A <- tibble(email=c("martingallardo23@gmail.com","raulgimenez@gmail.com"), 
            name=c("martin", "raul"), last_name=c("gallardo","gimenez"), 
            nombre_completo=c("martin gallardo", "raul gimenez"))


B <- tibble(email=c("martingallardo@gmail.com", "raulgimenez2@gmail.com"), 
            name=c("martin ricardo", "gimenez"), last_name=c("gallardo", "raul"), 
            nombre_completo=c("martin ricardo gallardo", "gimenez raul"), 
            other_data=c("A", "B"))

library(dplyr)
library(tidyr)
library(purrr)

A %>%
  rowwise() %>%
  mutate(nombre_completo2 = map_chr(nombre_completo, 
                                ~ B$nombre_completo
                                [str_detect(B$nombre_completo, str_sub(.x, 1L, 4L))])) %>%
  inner_join(B, by = c("nombre_completo2" = "nombre_completo")) %>%
  select(!ends_with(".y")) %>%
  rename_with(~ str_replace(., ".x", ""), ends_with(".x"))


# A tibble: 2 x 6
# Rowwise: 
  email                      name   last_name nombre_completo nombre_completo2       other_data
  <chr>                      <chr>  <chr>     <chr>           <chr>                  <chr>     
1 martingallardo23@gmail.com martin gallardo  martin gallardo martin ricardo gallar~ A         
2 raulgimenez@gmail.com      raul   gimenez   raul gimenez    gimenez raul           B 

【讨论】:

  • 这个也很有用。非常感谢!
  • 我很高兴,我还想在更大的数据集上测试它。请随时投票或选择符合您要求的每个答案。最良好的祝愿。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 2020-10-12
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 2014-03-04
相关资源
最近更新 更多