Группировать значения на основе вектора и столбца обновления

#r #dplyr

#r #dplyr

Вопрос:

Я пытаюсь сгруппировать различные значения на основе предопределенного вектора, а затем обновить столбец.

Пример данных

 df <- data.frame(ID = 1:5, Type = c("Windows", "Windows Server", "Cat", "Dog", "Eggs"))

it <- c("Windows", "Windows Server")
animal <- c("Cat", "Dog")
food <- c("Eggs")
  

Что я пробовал, но потерпел неудачу

 df$Grouping <- gsub(it, "IT", df$Type)
  

Ошибка: шаблон > 1

Метод, который работает, но многословен

Используя dplyr mutate, я смогу достичь того, чего я хочу, но это очень затянуто, поскольку у меня есть несколько элементов в векторе.

 df %>% mutate(Grouping = ifelse(Type == "Windows", "IT", 
                                ifelse ...))
  

Предполагаемый результат

 ID           Type         Grouping
1  1        Windows          IT
2  2 Windows Server          IT
3  3            Cat        Animal
4  4            Dog        Animal
5  5           Eggs        Food
  

Спасибо!

Комментарии:

1. Создать фрейм данных и объединить обратно?

2. Ваш gsub сбой, потому что вы предоставляете вектор в качестве выражения для поиска. Это сработает, если вы сделаете: gsub(paste(it, collapse = "|"), "IT", c("Windows", "Windows Server", "Cat", "Dog", "Eggs"))

3. @PavoDive это действительно полезно, спасибо!

Ответ №1:

Создайте список ваших предопределенных векторов, а затем проверьте, в каком элементе списка есть элементы внутри df$Type

 mylist = mget(c("animal", "food", "it"))
names(mylist)[max.col(t(sapply(df$Type, function(x) lapply(mylist, function(y) x %in% y))))]
#[1] "it"     "it"     "animal" "animal" "food"
  

Ответ №2:

Одним из вариантов было бы создать list (или a data.frame ) для сопоставлений, а затем выполнить left_join

 map <- list(
    it = c("Windows", "Windows Server"),
    animal = c("Cat", "Dog"),
    food = c("Eggs"))

library(dplyr)   
df %>% left_join(stack(map), by = c("Type" = "values"))
#  ID           Type    ind
#1  1        Windows     it
#2  2 Windows Server     it
#3  3            Cat animal
#4  4            Dog animal
#5  5           Eggs   food
  

Комментарии:

1. Спасибо за решение, это работает отлично! Однако у меня есть вопрос. Знаете ли вы, почему, когда я определяю свои векторы вне списка, stack(map) кажется, что это не работает? Он показывает мне эту ошибку: Error in data.frame(values = unlist(unname(x)), ind, stringsAsFactors = FALSE) : arguments imply differing number of rows: 5, 0

2. @Javier «Знаете ли вы, почему, когда я определяю свои векторы вне списка, stack(map) кажется, что это не работает?» Я не знаю, что это значит? Почему «вне list «? Вам нужно определить a list с именованными элементами. stack затем по строкам складываются записи из каждого list элемента в столбце values , а затем добавляется столбец ind , чтобы указать, из какого элемента они были получены.

3. Ах, я не знал, что в списке должны быть именованные элементы для stack работы. Большое спасибо!

Ответ №3:

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

с учетом сказанного, предполагая, что ваша проблема заключается в том, что векторы поиска хранятся в другом источнике и должны загружаться независимо, простого цикла должно быть достаточно. (Я использую data.table, потому что я даже больше не помню, как использовать необработанный data.frame):

 df <- data.table(ID = 1:5, Type = c("Windows", "Windows Server", "Cat", "Dog", "Eggs"))
it <- c("Windows", "Windows Server")
animal <- c("Cat", "Dog")
food <- c("Eggs")

lookup.names <- c("it", "animal", "food")
for (z in 1:length(lookup.names) ) {
    lookup <- get(lookup.names[z]) #maybe need to do some more sophisticated load, like from a file or database
    df[Type %in% lookup, Grouping := lookup.names[z]]
}
  

Комментарии:

1. Привет, опубликованный вопрос представляет собой смягченный, воспроизводимый пример моей проблемы. Цикл может быть не таким эффективным, поскольку я имею дело с большим набором данных; следовательно, использование left_join , предоставленное другими пользователями, работает лучше