Grepl в R, чтобы найти соответствия любому списку строк символов

Можно ли использовать аргумент grepl, ссылаясь на список значений, возможно, используя оператор% in%? Я хочу взять данные ниже, и если у животного есть "собака" или "кошка", я хочу вернуть определенное значение, скажем, "сохранить"; если у него нет "собаки" или "кошки", я хочу вернуть "отбросить".

data <- data.frame(animal = sample(c("cat","dog","bird", 'doggy','kittycat'), 50, replace = T))

Теперь, если бы я просто сделал это, строго сопоставив значения, скажем, "cat" и "dog", я мог бы использовать следующий подход:

matches <- c("cat","dog")

data$keep <- ifelse(data$animal %in% matches, "Keep", "Discard")

Но использование grep или grepl относится только к первому аргументу в списке:

data$keep <- ifelse(grepl(matches, data$animal), "Keep","Discard")

возвращает

Warning message:
In grepl(matches, data$animal) :
  argument 'pattern' has length > 1 and only the first element will be used

Заметьте, я видел этот поток в моем поиске, но это не работает: grep, используя вектор символов с несколькими шаблонами

Ответ 1

Вы можете использовать оператор "или" (|) внутри регулярного выражения grepl.

ifelse(grepl("dog|cat", data$animal), "keep", "discard")
# [1] "keep"    "keep"    "discard" "keep"    "keep"    "keep"    "keep"    "discard"
# [9] "keep"    "keep"    "keep"    "keep"    "keep"    "keep"    "discard" "keep"   
#[17] "discard" "keep"    "keep"    "discard" "keep"    "keep"    "discard" "keep"   
#[25] "keep"    "keep"    "keep"    "keep"    "keep"    "keep"    "keep"    "keep"   
#[33] "keep"    "discard" "keep"    "discard" "keep"    "discard" "keep"    "keep"   
#[41] "keep"    "keep"    "keep"    "keep"    "keep"    "keep"    "keep"    "keep"   
#[49] "keep"    "discard"

Регулярное выражение dog|cat указывает механизму регулярных выражений искать либо "dog", либо "cat", и возвращает совпадения для обоих.

Ответ 2

Старайтесь избегать ifelse как можно больше. Это, например, прекрасно работает

c("Discard", "Keep")[grepl("(dog|cat)", data$animal) + 1]

При значении 123 вы получите

##  [1] "Keep"    "Keep"    "Discard" "Keep"    "Keep"    "Keep"    "Discard" "Keep"   
##  [9] "Discard" "Discard" "Keep"    "Discard" "Keep"    "Discard" "Keep"    "Keep"   
## [17] "Keep"    "Keep"    "Keep"    "Keep"    "Keep"    "Keep"    "Keep"    "Keep"   
## [25] "Keep"    "Keep"    "Discard" "Discard" "Keep"    "Keep"    "Keep"    "Keep"   
## [33] "Keep"    "Keep"    "Keep"    "Discard" "Keep"    "Keep"    "Keep"    "Keep"   
## [41] "Keep"    "Discard" "Discard" "Keep"    "Keep"    "Keep"    "Keep"    "Discard"
## [49] "Keep"    "Keep"   

Ответ 3

Не уверен, что вы пробовали, но это работает:

data$keep <- ifelse(grepl(paste(matches, collapse = "|"), data$animal), "Keep","Discard")

Аналогично тому, как вы ответили.

Трюк использует пасту:

paste(matches, collapse = "|")
#[1] "cat|dog"

Таким образом, он создает регулярное выражение с собакой OR cat, а также будет работать с длинным списком шаблонов без ввода каждого из них.

Edit:

Если вы делаете это позже, подмножество data.frame в соответствии с записями "Keep" и "Discard", вы можете сделать это более непосредственно, используя:

data[grepl(paste(matches, collapse = "|"), data$animal),]

Таким образом, результаты для grepl, которые являются TRUE или FALSE, используются для подмножества.