【问题标题】:Conditionally mutate on partial string match across data frames of different lengths R/dplyr/stringr跨不同长度的数据帧 R/dplyr/stringr 对部分字符串匹配进行条件突变
【发布时间】:2021-05-11 02:55:19
【问题描述】:

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

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 列的见解,我将不胜感激。我也对非 dplyr/stringr 解决方案持开放态度。提前感谢您的帮助!

【问题讨论】:

    标签: r dplyr stringr


    【解决方案1】:
    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

    【讨论】:

    • 这些解决方案非常有效!我也从未考虑过使用名称的规律性首先对我有利。非常感谢您的帮助。
    【解决方案2】:

    您可以将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
    

    【讨论】:

    • 我真的很喜欢这种方法,看看它可以如何用于各种领域!非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-07-21
    • 2017-07-19
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 2014-09-20
    • 2014-07-13
    相关资源
    最近更新 更多