% как% с несколькими шаблонами в r - PullRequest
2 голосов
/ 06 февраля 2020

Можно ли использовать несколько шаблонов с% как% во вложенном ifelse? Если нет, то какой будет альтернатива?

fruits<-c("apple", "pineapple", "grape", "avocado","banana")

color <-c("red","yellow","purple", "green","yellow")

mydata = data.frame(fruits=fruits,color=color ) 


mydata %>%
  mutate(group = ifelse(fruits %like% c("%pple%","%vocado%"), "group 1",
                           ifelse(fruits %like% c("%anana%","%grape%"), "group 2", "group 3")))

Когда я пытаюсь выполнить приведенный выше код, я получаю следующую ошибку:

Warning messages:
1: In grep(pattern, levels(vector)) :
  argument 'pattern' has length > 1 and only the first element will be used
2: In grep(pattern, levels(vector)) :
  argument 'pattern' has length > 1 and only the first element will be used

Любое руководство приветствуется. Спасибо!

Ответы [ 2 ]

3 голосов
/ 06 февраля 2020

Вы можете sapply на шаблонах и суммировать строки, чтобы найти то, что вам нужно.

Примечания:

  • Я конвертирую ваши SQL -эскизовые шаблоны для регулярного выражения здесь.
  • при использовании dplyr, вероятно, лучше использовать его if_else, так как эта версия лучше защищает от выходов различных классов (а также от некоторых других проблем с базой ifelse).
  • Поскольку %like% является просто инфиксным оператором для функции like (по крайней мере, в data.table), для ясности я использую последний вариант (версия с предварительным исправлением).
sapply(c(".*apple.*", ".*vocado.*"), like, vector = fruits)
#      .*apple.* .*vocado.*
# [1,]      TRUE      FALSE
# [2,]      TRUE      FALSE
# [3,]     FALSE      FALSE
# [4,]     FALSE       TRUE
# [5,]     FALSE      FALSE
rowSums(sapply(c(".*apple.*", ".*vocado.*"), like, vector = fruits)) > 0
# [1]  TRUE  TRUE FALSE  TRUE FALSE

Это то, что нам нужно, вектор logical. Я сделаю вспомогательную функцию для этого.

mylike <- function(x, ptns) rowSums(sapply(ptns, like, vector = x)) > 0
mylike(fruits, c(".*apple.*", ".*vocado.*"))
# [1]  TRUE  TRUE FALSE  TRUE FALSE
mydata %>%
  mutate(
    group = if_else(mylike(fruits, c(".*apple.*", ".*vocado.*")), "group 1",
                    if_else(mylike(fruits, c(".*anana.*",".*grape.*")), "group 2", "group 3"))
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2

Однако, когда я вижу вложенный ifelse / if_else, я предлагаю case_when, так как он гораздо более читабелен, особенно когда число условий увеличивается.

mydata %>%
  mutate(
    group = case_when(
      mylike(fruits, c(".*apple.*", ".*vocado.*")) ~ "group 1",
      mylike(fruits, c(".*anana.*",".*grape.*"))   ~ "group 2",
      TRUE                                         ~ "group 3"
    )
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2

Если у вас уже есть набор SQL шаблонов и вы не хотите переводить их все в регулярные выражения, вот быстрая вспомогательная функция, основанная на https://codereview.stackexchange.com/a/36864/42300:

# https://codereview.stackexchange.com/a/36864/42300
sql2regex <- function(ptn) {
  paste0(
    "^",
    gsub("_", ".",
         gsub("(?<!\\[)%(?!\\])", ".*", ptn, perl = TRUE)),
    "$")
}

Он пытается быть умным, чтобы не конвертировать [%], что является одним из способов "избежать" процента и go для его литерала (ref: http://www.sqlserver.info/syntax/sql-server-like-with-percent-literal/). Однако, даже если [% может показаться неполным, это неверно переведено в ^[.*$, вместо этого оно остается ^[%$, что приведет к ошибке. Опять же, это всего лишь вспомогательная функция быстрого взлома.

mydata %>%
  mutate(
    group = case_when(
      mylike(fruits, sql2regex(c("%pple%","%vocado%"))) ~ "group 1",
      mylike(fruits, sql2regex(c("%anana%","%grape%"))) ~ "group 2",
      TRUE ~ "group 3"
    )
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2
2 голосов
/ 07 февраля 2020
Функция

data.table like() и ее версии операторов %like%, %ilike% и %flike% допускают только один параметр шаблона, но вы можете использовать alternation в регулярном выражении. Чередование выражается вертикальной чертой:

library(data.table)
library(dplyr)
mydata %>%
  mutate(group = ifelse(fruits %ilike% "apple|avocado", "group 1",
                        ifelse(fruits %ilike% "banana|grape", "group 2", "group 3")))
     fruits  color   group
1     apple    red group 1
2 pineapple yellow group 1
3     grape purple group 2
4   avocado  green group 1
5    banana yellow group 2

Итак, group 1 соответствует любой строке, где либо apple, либо avocado появляется в любом месте в строке. Следовательно, % для указания произвольного числа произвольных символов не требуется.

Обратите внимание, что вместо %like% было использовано %ilike%. %ilike% - это новые вспомогательные функции, которые предназначены для сопоставления с учетом регистра без учета регистра и которые стали доступны в data.table v1.12.4 (в CRAN с 3 октября 2019 г.).

%ilike% также будет соответствовать слову Apple (с большой буквы A).

Конечно, case_when() является хорошей альтернативой вложенному ifelse(), как предлагает r2evans :

mydata %>%
  mutate(group = case_when(fruits %ilike% "apple|avocado" ~ "group 1",
                           fruits %ilike% "banana|grape" ~ "group 2", 
                           TRUE ~ "group 3"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...