有条件地改变不同长度数据帧的部分字符串匹配 R/dplyr/stringr

Conditionally mutate on partial string match across data frames of different lengths R/dplyr/stringr

我有两个不同长度的数据框,都是字符串。比方说:

NameDF <- data.frame (names  = c("Jane","John"))
JobDF <- data.frame (occupation  = c("Frank is a teacher","Jane is a doctor","John cooks part-time","Mike was a musician","Jane is an engineer"))

在真实数据集中,NameDF是一个用户指定的列,会在2-5个名字(行)之间变化。 JobDF 的长度在 65-70 行之间。有时 NameDF$names 中的名字在 JobDF$occupation 中出现不止一次。每次使用脚本时,两者的内容都会有所不同。

我的目标是在 JobDF 中创建一个名为 inNameDF 的新列,具体取决于名称是否出现在 NameDF 中。

我的预期输出如下所示:

JobDF
rowID      occupation        inNameDF
1      Frank is a teacher       no
2      Jane is a doctor         yes
3      John cooks part-time     yes
4      Mike was a musician      no
5      Jane is an engineer      yes

因为 NameDF 和 JobDF 的内容和长度总是不同,所以我开始使用 %in%。但这不起作用,因为我需要部分字符串检测才能在 JobDF$occupation 中进行模式匹配。然后我转向使用 grepl,但它只检测第一行(在我的例子中是 Jane),而不检测其他行。我得到的最接近的是:

library(dplyr)
library(stringr)
JobDF %>% 
   mutate(inNameDF = ifelse(str_detect(occupation, NameDF$names),"yes","no"))

这给出了与 grepl 类似的警告消息,因为它只处理 NameDF 中第一个案例的最后一个实例(Jane 的最后一个实例)。在这一点上,我已经转了几天了,如果能提供有关如何获取 JobDF$inNameDF 列的任何见解,我将不胜感激。我也愿意接受 non-dplyr/stringr 解决方案。预先感谢您的帮助!

library(dplyr)

JobDF %>% 
    mutate(inNameDF = ifelse(str_detect(occupation, paste0(NameDF$names, collapse = "|")),"yes","no"))

paste0 的输出是这样的:

paste0(NameDF$names, collapse = "|")

[1] "Jane|John"

这是匹配“Jane”“John”的正则表达式。如果您需要匹配不区分大小写,则将其包装在 stringr::regex 中,如下所示:regex(paste0(...), ignore_case = T).


如果名字总是第一个词,那么你也可以这样做:

ifelse(sapply(str_split(JobDF$occupation, " "), `[[`, 1) %in% NameDF$names, "yes", "no")

[1] "no"  "yes" "yes" "no"  "yes"

occupation 中提取第一个单词并检查它是否是 %in% names.

您可以将 NameDF 中的 names 折叠成一个带有单词边界 (\b) 的字符串,并使用 ifelse 分配 'yes''no'。需要字边界,以便 'Jane''Janesen' 等不匹配

JobDF$inNameDF <- ifelse(grepl(paste0('\b', NameDF$names, '\b', collapse = '|'), 
                         JobDF$occupation), 'yes', 'no')
JobDF

#            occupation inNameDF
#1   Frank is a teacher       no
#2     Jane is a doctor      yes
#3 John cooks part-time      yes
#4  Mike was a musician       no
#5  Jane is an engineer      yes