A series of wild cards in STR_DETECT in R

Viewed 87

I use STR_DETECT with IFELSE to create a new column called "function_YN". However, since I have to throw in a large number of wild cards, my script became long and cumbersome. Any way to simply this? Below is just a shortened version of the coding and I actually have more key words to detect.

library(dplyr)
library(stringr)
df$function_YN <- 
ifelse(str_detect(df$JOB_TITLE, "POLICE"),"YES",
ifelse(str_detect(df$JOB_TITLE, "FIREFIGHTER"),"YES",
ifelse(str_detect(df$JOB_TITLE, "DETECTIVE"),"YES",
ifelse(str_detect(df$JOB_TITLE, "PUBLIC SAFETY"),"YES",
ifelse(str_detect(t1$JOB_TITLE, "CAPTAIN"),"YES", "NO")))))
2 Answers

Instead of multiple ifelse statement, just create a single pattern for the POLICE, 'FIREFIGHTER' etc. with str_c and then convert the logical to numeric index by adding 1 (TRUE -> 1, FALSE -> 0 when added 1, changes to 2 and 1 respectively). Then, using the index as position, replace the position with vector of values ("NO", "YES") - (NOTE: In R indexing starts from 1)

library(stringr)
yes_words <- c("POLICE", "FIREFIGHTER", "DETECTIVE", "PUBLIC SAFETY", "CAPTAIN")
pat <- str_c("\\b(", str_c(yes_words, collapse = "|"), ")\\b")
df$function_YN <- c("NO", "YES")[ 1 + str_detect(df$JOBTITLE, pat)]

Another alternative:

str_detect_any <- function(x, target_list) {
   found_any <- rep(FALSE, length(x))
   for (s in target_list) {
      found_any <- found_any | str_detect(x, s)
   }
   return(found_any)
}

Then

yes_words <- c("POLICE", "FIREFIGHTER", "DETECTIVE", "PUBLIC SAFETY", "CAPTAIN")
df$function_YN <- ifelse(str_detect_any(df$JOB_TITLE, yes_words), "YES", "NO")

(untested). A more compact and less comprehensible version could probably be constructed using Reduce() ...

This does require multiple passes through the string. If all of your targets are fixed strings rather than regular expressions, you could use fixed() (this is in the documentation for str_detect, but I don't actually know how to use it ...), which would make things faster.

Related