Совпадение частичных животных в R

У меня есть dataframe,

d<-data.frame(name=c("brown cat", "blue cat", "big lion", "tall tiger",
                     "black panther", "short cat", "red bird",
                     "short bird stuffed", "big eagle", "bad sparrow",
                     "dog fish", "head dog", "brown yorkie",
                     "lab short bulldog"), label=1:14)

Я бы хотел найти столбец name, и если слова "cat", "lion", "tiger" и "panther", я хочу присвоить символьную строку feline новому столбцу и соответствующей строке species.

Если появляются слова "bird", "eagle", and "sparrow", я хочу присвоить символьную строку avian новому столбцу и соответствующей строке species.

Если появляются слова "собака", "йорки" и "бульдог", я хочу присвоить символьную строку canine новому столбцу и соответствующей строке species.

В идеале я бы сохранил это в списке или что-то подобное, что я могу сохранить в начале script, потому что, поскольку новые варианты вида появляются в названии категории, было бы неплохо иметь доступ к обновлению, что соответствует feline, avian и canine.

На этот вопрос почти ответили (Как создать новый столбец в dataframe на основе частичной строки, сопоставляющей другой столбец в R), но он не затрагивает множественные имя, которое присутствует в этой проблеме.

Ответы

Ответ 1

Может быть более элегантное решение, чем это, но вы можете использовать grep с | для указания альтернативных совпадений.

d[grep("cat|lion|tiger|panther", d$name), "species"] <- "feline"
d[grep("bird|eagle|sparrow", d$name), "species"] <- "avian"
d[grep("dog|yorkie", d$name), "species"] <- "canine"

Я предположил, что вы имели в виду "птичий", и оставили "бульдога", так как он содержит "собаку".

Вы можете добавить ignore.case = TRUE в grep.

выход:

#                 name label species
#1           brown cat     1  feline
#2            blue cat     2  feline
#3            big lion     3  feline
#4          tall tiger     4  feline
#5       black panther     5  feline
#6           short cat     6  feline
#7            red bird     7   avian
#8  short bird stuffed     8   avian
#9           big eagle     9   avian
#10        bad sparrow    10   avian
#11           dog fish    11  canine
#12           head dog    12  canine
#13       brown yorkie    13  canine
#14  lab short bulldog    14  canine

Ответ 2

Элегантный способ сделать это (я говорю элегантно-иш, потому что, хотя это самый элегантный способ, о котором я знаю, это не очень), это что-то вроде:

#Define the regexes at the beginning of the code
regexes <- list(c("(cat|lion|tiger|panther)","feline"),
                c("(bird|eagle|sparrow)","avian"),
                c("(dog|yorkie|bulldog)","canine"))

....


#Create a vector, the same length as the df
output_vector <- character(nrow(d))

#For each regex..
for(i in seq_along(regexes)){

    #Grep through d$name, and when you find matches, insert the relevant 'tag' into
    #The output vector
    output_vector[grepl(x = d$name, pattern = regexes[[i]][1])] <- regexes[[i]][2]

} 

#Insert that now-filled output vector into the dataframe
d$species <- output_vector

Преимущество этого метода заключается в нескольких вариантах

  • Вам нужно только изменить кадр данных один раз в течение всего процесса, что увеличивает скорость цикла (кадры данных не имеют модификации на месте, чтобы изменить кадр данных 3 раза, вы по существу перемаркированы и воссоздавая его 3 раза).
  • Указав длину вектора заранее, так как мы знаем, что это будет, вы увеличиваете скорость еще больше, гарантируя, что выходному вектору никогда не понадобится больше памяти, выделенной после его создания.
  • Поскольку это цикл, а не повторные ручные вызовы, добавление большего количества строк и категорий в объект 'regexes' не потребует дальнейшей модификации кода. Он будет работать так же, как сейчас.

Единственный недостаток - и это относится, по-моему, к большинству решений, которые вы, скорее всего, получите, состоит в том, что если что-то соответствует нескольким шаблонам, последний шаблон в списке, который он соответствует, будет его тегом вида.