Как обнаружить более одного регулярного выражения в выражении case_when - PullRequest
0 голосов
/ 19 декабря 2018

Я недавно перешел из ifelse в case_when из dplyr.

Цель

Я хотел бы иметь возможность обнаруживать более одного регулярного выражения из оператора в кадре данных, используя case_when следующим образом:

Вход

statement<-data.frame(statement = c("I have performed APC and RFA",
 "An EMR was done","I didn't do anything"),stringsAsFactors=FALSE)

Желаемый вывод

statement                            out

I have performed APC and RFA        APC,RFA
An EMR was done                     EMR
I didn't do anything                No Event

Попытка

library(dplyr)
library(stringr)

      dataframe <- 
        dataframe %>% 
        mutate(
          EVENT = case_when(
            str_detect(statement,"EMR") ~ "EMR", 
            str_detect(statement, "HALO|RFA") ~ "RFA", 
            str_detect(statement, "APC") ~ "APC", 
             TRUE ~ "No Event"
          )
        )

Проблема

Это дает только один вывод на оператор вместо нескольких выходных, если присутствует несколько строк.Есть ли способ обнаружить несколько строк?

Ответы [ 4 ]

0 голосов
/ 19 декабря 2018

Я не думаю, что case_when - лучший путь.Я думаю, что это немного зависит от того, сколько отображений типа "HALO|RFA" у вас есть.Если их много, возможно, стоит написать правильную функцию.Однако, если это только этот, может быть быстрее собрать трубу, используя глаголы dplyr.

Я бы предложил использовать str_extract_all и unnest, чтобы получить аккуратный кадр данных с соответствующими глаголами, а затем использовать str_replace_all для разрешения сопоставления.В конце я бы использовал unique, чтобы убедиться, что у нас нет повторяющихся строк из замен.

Обратите внимание, что первый столбец с APC, RFA будет разделен на две части.Я понимаю, что это не то, что вы просили, но это значительно упростит последующую обработку в Tidyverse.Смотрите эту ссылку для более подробной информации об условных обозначениях: https://tidyr.tidyverse.org/articles/tidy-data.html

В текущей реализации unnest удалит последнюю строку, в которой не было найдено ни одного шаблона.Если вы хотите вместо этого NA, вы можете выполнить full join с исходными данными.См. Также https://github.com/tidyverse/tidyr/issues/358

statement<-data.frame(statement = c("I have performed APC and RFA","An EMR was done","I didn't do anything"),stringsAsFactors=FALSE)
library(tidyverse)
statement %>% mutate(
  out = statement %>% 
    str_extract_all("((EMR)|(HALO)|(RFA)|(APC))")
  ) %>%  unnest(.drop =FALSE) %>% 
  mutate(
    out = out %>% str_replace_all("HALO", "RFA")
  ) %>% 
  unique() %>% 
  full_join(statement)

Выход будет

                 statement    out
I have performed APC and RFA  APC
I have performed APC and RFA  RFA
An EMR was done               EMR
I didn't do anything          <NA>
0 голосов
/ 19 декабря 2018

1) gsubfn :: strapply strapply может выполнять извлечение и перевод одновременно.strapply для каждого компонента stmt будет соответствовать шаблону pat, и все совпадения будут переведены с использованием L, а затем возвращены.Аргумент empty определяет, что возвращается для компонентов stat, не имеющих совпадений.Это дает список совпадений, один компонент списка на строку, к которому применяется toString для преобразования каждого в разделенную запятыми символьную строку.Это самая короткая из 3 представленных здесь альтернатив.

library(gsubfn)

L <- list(APC = "APC", EMR = "EMR", HALO = "RFA", RFA = "RFA")
pat <- paste(names(L), collapse = "|")
transform(statement, 
  out = sapply(strapply(stmt, pat, L, empty = "No Event"), toString),
  stringsAsFactors = FALSE)

, дающая:

                          stmt      out
1 I have performed APC and RFA APC, RFA
2              An EMR was done      EMR
3         I didn't do anything No Event

2) База R Использование L и pat извыше, создайте функцию, которая берет символьный вектор слов x и извлекает те слова, которые соответствуют pat в g.Если g имеет ненулевую длину, переведите его элементы, используя L, и сожмите его в одну строку, используя toString;в противном случае верните No Event.

Теперь разделите каждый элемент stmt на слова, используя strsplit, и примените process к каждому такому вектору символов.

process <- function(x) {
  g <- grep(pat, x, value = TRUE)
  if (length(g)) toString(L[g]) else "No Event"
}
transform(statement, out = sapply(strsplit(stmt, "\\s+"), process),
  stringsAsFactors = FALSE)

3) dplyr / tidyr Используя L из (1), сгруппируйте по номеру строки и stmt и разделите слова на отдельные строки.Отфильтруйте эти слова в names(L) и сверните все строки в одну группу stmt, переводя через L и используя toString, чтобы создать строку через запятую.Оставьте столбец n.На данный момент у нас есть желаемый результат, за исключением того, что No Event строк по-прежнему не хватает, поэтому объедините правильные значения с statement и замените NA на No Event.

library(dplyr)
library(tidyr)

statement %>%
  group_by(n = 1:n(), out = stmt) %>%
  separate_rows(out) %>%
  filter(out %in% names(L)) %>%
  summarize(stmt = stmt[1], out = toString(L[out])) %>%
  ungroup %>%
  select(-n) %>%
  right_join(statement, by = "stmt") %>%
  mutate(out = if_else(is.na(out), "No Event", out))

, получив:

# A tibble: 3 x 2
  stmt                         out     
  <chr>                        <chr>   
1 I have performed APC and RFA APC, RFA
2 An EMR was done              EMR     
3 I didn't do anything         No Event

Примечание

Мы использовали это в качестве ввода:

statement <- structure(list(stmt = c("I have performed APC and RFA", 
  "An EMR was done", "I didn't do anything")), 
  class = "data.frame", row.names = c(NA, -3L))

Обновления

Несколько раз пересматривали после повторного чтения вопроса.Также добавлено больше альтернатив.

0 голосов
/ 19 декабря 2018

Логика case_when заключается в том, что он не выполняет оставшиеся условия после выполнения условия, поэтому вы не можете получить два выхода из оператора case_when.Поэтому, если вы хотите использовать case_when, рекомендуется начинать с наименьшего общего условия, а затем постепенно делать его более общим.(следовательно, TRUE является последним условием)

Если вы хотите придерживаться case_when, вы можете добавить дополнительное условие и проверить оба случая в отдельности и выдать соответствующий вывод.

library(dplyr)

statement %>% 
     mutate(
     EVENT = case_when(
           str_detect(statement, "APC") & str_detect(statement, "RFA") ~ "APC,RFA",
           str_detect(statement,"EMR") ~ "EMR", 
           str_detect(statement, "HALO|RFA") ~ "RFA", 
           str_detect(statement, "APC") ~ "APC", 
           TRUE ~ "No Event"
            )
           )



#                     statement    EVENT
#1 I have performed APC and RFA  APC,RFA
#2              An EMR was done      EMR
#3         I didn't do anything No Event
#4                        FALSE No Event
0 голосов
/ 19 декабря 2018

Идея с помощью базы R состоит в том, чтобы извлечь слова со всеми заглавными буквами и вставить те, которые больше 1 символа, т.е.

sapply(regmatches(statement$statement, gregexpr('\\b[A-Z]+\\b', statement$statement)), 
                                          function(i) {
                                                      v1 <- i[nchar(i) > 1];
                                                      toString(v1)
                                                      })


#[1] "APC, RFA" "EMR"      ""
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...