【问题标题】:multiple patterns for string matching using case_when使用 case_when 进行字符串匹配的多种模式
【发布时间】:2019-11-28 05:26:38
【问题描述】:

我正在尝试使用 str_detect 和 case_when 根据多种模式重新编码字符串,并将每次出现的重新编码值粘贴到一个新列中。正确的列是我想要实现的输出。

这类似于this questionthis question 如果不能用case_when(我认为仅限于一种模式)完成,是否有更好的方法仍然可以使用tidyverse 来实现?

Fruit=c("Apples","apples, maybe bananas","Oranges","grapes w apples","pears")
Num=c(1,2,3,4,5)
data=data.frame(Num,Fruit)

df= data %>% mutate(Incorrect=
paste(case_when(
  str_detect(Fruit, regex("apples", ignore_case=TRUE)) ~ "good",
  str_detect(Fruit, regex("bananas", ignore_case=TRUE)) ~ "gross",
  str_detect(Fruit, regex("grapes | oranges", ignore_case=TRUE)) ~ "ok",
  str_detect(Fruit, regex("lemon", ignore_case=TRUE)) ~ "sour",
  TRUE ~ "other"
),sep=","))

  Num                 Fruit Incorrect
  1                Apples      good
  2 apples, maybe bananas      good
  3               Oranges      other
  4       grapes w apples      good
  5                pears       other

 Num                 Fruit    Correct
   1                Apples       good
   2 apples, maybe bananas good,gross
   3               Oranges         ok
   4       grapes w apples    ok,good
   5                pears       other

【问题讨论】:

标签: r tidyverse case-when


【解决方案1】:

case_when 中,如果满足某一行的条件,它将停在那里并且不再检查任何其他条件。因此,通常在这种情况下,最好将每个条目放在单独的行中,以便更容易分配值,然后将 summarise 全部放在一起。但是,在这种情况下,Fruit 列没有明确的分隔符,一些水果用逗号分隔(,),一些带有空格,并且它们之间还有额外的单词。为了处理所有此类情况,我们将NA 分配给不匹配的单词,然后在汇总期间将其删除。

library(dplyr)
library(stringr)

data %>%
  tidyr::separate_rows(Fruit, sep = ",|\\s+") %>%
   mutate(Correct = case_when(
      str_detect(Fruit, regex("apples", ignore_case=TRUE)) ~ "good",
      str_detect(Fruit, regex("bananas", ignore_case=TRUE)) ~ "gross",
      str_detect(Fruit, regex("grapes|oranges", ignore_case=TRUE)) ~ "ok",
      str_detect(Fruit, regex("lemon", ignore_case=TRUE)) ~ "sour",
      TRUE ~ NA_character_)) %>% 
   group_by(Num) %>%
   summarise(Correct = toString(na.omit(Correct))) %>%
   left_join(data)

#   Num Correct     Fruit                
#  <dbl> <chr>       <fct>                
#1     1 good        Apples               
#2     2 good, gross apples, maybe bananas
#3     3 ok          Oranges              
#4     4 ok, good    grapes w apples      
#5     5 sour        Lemons               

对于更新后的数据,我们可以去掉出现的多余单词并做

data %>%
  mutate(Fruit = gsub("maybe|w", "", Fruit)) %>%
  tidyr::separate_rows(Fruit, sep = ",\\s+|\\s+") %>%
  mutate(Correct = case_when(
     str_detect(Fruit, regex("apples", ignore_case=TRUE)) ~ "good",
     str_detect(Fruit, regex("bananas", ignore_case=TRUE)) ~ "gross",
     str_detect(Fruit, regex("grapes|oranges", ignore_case=TRUE)) ~ "ok",
     str_detect(Fruit, regex("lemon", ignore_case=TRUE)) ~ "sour",
     TRUE ~ "other")) %>% 
  group_by(Num) %>%
  summarise(Correct = toString(na.omit(Correct))) %>%
  left_join(data)

#    Num Correct     Fruit                
#  <dbl> <chr>       <fct>                
#1     1 good        Apples               
#2     2 good, gross apples, maybe bananas
#3     3 ok          Oranges              
#4     4 ok, good    grapes w apples      
#5     5 other       pears                

【讨论】:

  • 唯一的问题是 TRUE ~ NA_character_ 。我希望将有意义的不匹配字符串编码为TRUE ~ other。我编辑了数据以更好地反映我的实际数据。 @RonakShah
  • @W148SMH 正如我的帖子中提到的,问题的出现是因为每个水果之间没有明确的分隔符。有时它们用逗号分隔,有时用空格分隔。所以我把两者分开了,但是已经有一些不匹配的词,比如maybew。如果我们给TRUE ~ 'other',那么这些词也将被分配'other'
  • 如果我在开头删除 maybewstr_replace(Fruit,"maybe|w","")) 之类的东西,它仍然想在删除这些词后添加 other @RonakShah
  • @W148SMH 是的,如果这些是唯一出现的单词,那么您可以删除它们。查看更新的答案。
  • 完美!谢谢
猜你喜欢
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
相关资源
最近更新 更多