r - str_detect 在同一行的多列上

标签 r stringr

我有两个数据集,一个包含全名,另一个包含名字和姓氏。

library(tidyverse)
(x = tibble(fullname = c("Michael Smith", 
                         "Elisabeth Brown", 
                         "John-Henry Albert")))
#> # A tibble: 3 x 1
#>   fullname         
#>   <chr>            
#> 1 Michael Smith    
#> 2 Elisabeth Brown  
#> 3 John-Henry Albert

(y = tribble(~first, ~last,
            "Elisabeth", "Smith",
            "John", "Albert",
            "Roland", "Brown"))
#> # A tibble: 3 x 2
#>   first     last  
#>   <chr>     <chr> 
#> 1 Elisabeth Smith 
#> 2 John      Albert
#> 3 Roland    Brown

我想创建一个 bool 列,仅当第一列和最后一列位于全名列内时该列才为 true。

本质上,我正在寻找类似的东西:

x %>% 
  mutate(fname_match = str_detect(fullname, paste0(y$first, collapse = "|")), ## correct 
         lname_match = str_detect(fullname, paste0(y$last, collapse = "|"))) ## correct
#> # A tibble: 3 x 3
#>   fullname          fname_match lname_match
#>   <chr>             <lgl>       <lgl>      
#> 1 Michael Smith     FALSE       TRUE       
#> 2 Elisabeth Brown   TRUE        TRUE       
#> 3 John-Henry Albert TRUE        TRUE

但在这里,如果我采用具有两个 TRUE 的 Elisabeth Brown 的列,则会出现误报,因为匹配的名字和姓氏不在同一行中。

到目前为止,我最好的想法是结合第一列和最后一列并搜索它,但这会给 John-Henry 带来假阴性

y = tribble(~first, ~last,
            "Elisabeth", "Smith",
            "John", "Albert",
            "Roland", "Brown") %>% 
    rowwise() %>% 
    mutate(longname = paste(first, last, sep = "&"))


x %>% 
  mutate(full_match = str_detect(fullname, paste0(y$longname, collapse = "|")))
#> # A tibble: 3 x 2
#>   fullname          full_match
#>   <chr>             <lgl>     
#> 1 Michael Smith     FALSE     
#> 2 Elisabeth Brown   FALSE     
#> 3 John-Henry Albert FALSE

最佳答案

我认为这可以满足您的需求,使用 purrr::map2 迭代 firstlast 的元组。

library(dplyr)
library(purrr)

y %>%
  mutate(
    name_match = map2_lgl(
      first, last, 
      .f = ~any(grepl(paste0(.x, '.*', .y), x$fullname, ignore.case = T))
    )
  )

请注意,paste0(.x, '.*', .y) 将它们组合成一个正则表达式,该正则表达式只允许姓氏完全出现在之后 第一个。这似乎是合理的(否则,名字“Elisabeth”,姓氏“Abe”仍然是TRUE,我在这里假设你不会想要)。 另外,以上内容不区分大小写

//更新:
我忘了;相反,如果您想检查 x 中的 fullname 值,那么您可以运行以下命令:

x %>%
  rowwise() %>%
  mutate(
    name_match = any(map2_lgl(
      y$first, y$last,
      .f = ~grepl(paste0('\\b', .x, '\\b.*\\b', .y, '\\b'), fullname, ignore.case = T)
    ))
  )

根据此检查对您的重要性以及您想要做出多少假设,进一步调整上述正则表达式可能是有意义的:

  1. 确保名字和姓氏为 isolated words全名
    -> paste0('\\b', .x, '\\b.*\\b', .y, '\\b')
  2. 测试名字是否出现在开头
    -> paste0('^', .x, '\\b.*\\b', .y, '\\b')
  3. 测试全名是否在姓氏之后结束
    -> paste0('\\b', .x, '\\b.*\\b', .y, '$')

关于r - str_detect 在同一行的多列上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63779907/

相关文章:

r - "A"= "a"、 "B"= "b"等形式的表达式如何从 LETTERS 和字母自动构建?

r - 如何将数据框列名插入方程式 R?

r - R 中的绘图函数在不调用 legend() 的情况下生成图例

windows - 是否可以检索使用 file.remove 删除的文件?

r - stringr 相当于 grep

r - 使用 Slice 或 Stringr 更改 R 中字符串向量中特定字符串的位置?

删除字符串的重复元素

r - geom_rect和ggplot2错误: Aesthetics must be either length 1 or the same as the data (2)

r - 软件包 ‘stringr’ 和 ‘stringi’ 的安装具有非零退出状态

r - str_replace_all 不适用于包含括号的字符串