有条件地改变不同长度数据帧的部分字符串匹配 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
我有两个不同长度的数据框,都是字符串。比方说:
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