str_detect在同一行中的多列上

问题描述

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

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

我想只在第一列和最后一列在全名列内的情况下,才创建一个布尔值列。

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

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,"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,我在这里假定您不希望这样做)。 另外,上面的代码不区分大小写。

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

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','\\b')
  2. 测试名字的开头是否正确
    -> paste0('^','\\b')
  3. 测试全名以姓氏结尾
    -> paste0('\\b','$')

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...