несколько шаблонов для сопоставления строк с использованием case_when

Я пытаюсь использовать str_detect и case_when для перекодирования строк на основе нескольких шаблонов и вставки каждого случая перекодированного значения (значений) в новый столбец. Столбец "Правильный" - это результат, которого я пытаюсь достичь.

Это похоже на этот вопрос и этот вопрос Если это не может быть выполнено с помощью 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

person W148SMH    schedule 28.11.2019    source источник
comment
Связанный stackoverflow.com/questions/53851627/ & stackoverflow.com/questions/56588108/   -  person Tung    schedule 13.11.2020


Ответы (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                
person Ronak Shah    schedule 28.11.2019
comment
Единственная проблема - TRUE ~ NA_character_. Я хочу, чтобы значимые несоответствующие строки были закодированы как TRUE ~ other. Я отредактировал данные, чтобы лучше отразить мои фактические данные. @RonakShah - person W148SMH; 30.11.2019
comment
@ W148SMH Как упоминалось в моем сообщении, проблема возникает из-за отсутствия четкого разделителя между фруктами. Иногда они разделяются запятой, иногда пробелом. Итак, я разделил оба слова, но уже есть несколько несовпадающих слов, например maybe, w. Если мы дадим TRUE ~ 'other', этим словам также будет присвоено 'other'. - person Ronak Shah; 30.11.2019
comment
Если я удалю maybe и w в начале с чем-то вроде str_replace(Fruit,"maybe|w","")), он все равно захочет добавить other после удаления этих слов @RonakShah - person W148SMH; 30.11.2019
comment
@ W148SMH да, если это единственные слова, вы можете их удалить. См. Обновленный ответ. - person Ronak Shah; 30.11.2019
comment
Идеально! Спасибо - person W148SMH; 30.11.2019