我有两个数据集,一个包含全名,另一个包含名字和姓氏。
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 迭代 first
和 last
的元组。
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)
))
)
根据此检查对您的重要性以及您想要做出多少假设,进一步调整上述正则表达式可能是有意义的:
- 确保名字和姓氏为 isolated words全名
->paste0('\\b', .x, '\\b.*\\b', .y, '\\b')
- 测试名字是否出现在开头
->paste0('^', .x, '\\b.*\\b', .y, '\\b')
- 测试全名是否在姓氏之后结束
->paste0('\\b', .x, '\\b.*\\b', .y, '$')
关于r - str_detect 在同一行的多列上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63779907/