Существует ли функция dplyr для определения наиболее часто встречающегося категориального значения в группе?
Я хочу суммировать данные транзакции клиента в одну строку для каждого клиента, используя dplyr. Для непрерывных переменных это просто - используйте сумму / среднее и т. Д. Для категориальных переменных я бы хотел выбрать "Режим" - то есть наиболее часто встречающееся значение в группе и сделать это в нескольких столбцах, например:
Например взять таблицу Cus1
Cus <- data.frame(Customer = c("C-01", "C-01", "C-02", "C-02", "C-02", "C-02", "C-03", "C-03"),
Product = c("COKE", "COKE", "FRIES", "SHAKE", "BURGER", "BURGER", "CHICKEN", "FISH"),
Store = c("NYC", "NYC", "Chicago", "Chicago", "Detroit", "Detroit", "LA", "San Fran")
)
И сгенерируем таблицу Cus_Summary:
Cus_Summary <- data.frame(Customer = c("C-01", "C-02", "C-03"),
Product = c("COKE", "BURGER", "CHICKEN"),
Store = c("NYC", "Chicago", "LA")
)
Есть ли пакеты, которые могут предоставить эту функцию? Или есть кто-нибудь функция, которая может быть применена к нескольким столбцам в шаге dplyr?
Я не беспокоюсь об умных способах обработки связей - любой вывод для связи будет достаточным (хотя любые предложения относительно того, как лучше всего обрабатывать связи, были бы интересны и оценены).
4 ответа
Как насчет этого?
Cus %>%
group_by(Customer) %>%
summarise(
Product = first(names(sort(table(Product), decreasing = TRUE))),
Store = first(names(sort(table(Store), decreasing = TRUE))))
## A tibble: 3 x 3
# Customer Product Store
# <fct> <chr> <chr>
#1 C-01 COKE NYC
#2 C-02 BURGER Chicago
#3 C-03 CHICKEN LA
Обратите внимание, что в случае связей это выбирает первую запись в алфавитном порядке.
Обновить
Чтобы случайным образом выбрать запись из привязанных записей с высокой частотой, мы могли бы определить пользовательскую функцию
top_random <- function(x) {
tbl <- sort(table(x), decreasing = T)
top <- tbl[tbl == max(tbl)]
return(sample(names(top), 1))
}
Затем следующее случайным образом выбирает одну из связанных записей сверху:
Cus %>%
group_by(Customer) %>%
summarise(
Product = top_random(Product),
Store = top_random(Store))
В моем решении, если есть более одного наиболее частого значения, все представлены:
library(tidyverse)
Cus %>%
gather('type', 'value', -Customer) %>%
group_by(Customer, type, value) %>%
count() %>%
group_by(Customer) %>%
filter(n == max(n)) %>%
nest() %>%
mutate(
Product = map_chr(data, ~str_c(filter(.x, type == 'Product') %>% pull(value), collapse = ', ')),
Store = map_chr(data, ~str_c(filter(.x, type == 'Store') %>% pull(value), collapse = ', '))
) %>%
select(-data)
Результат:
# A tibble: 3 x 3
Customer Product Store
<fct> <chr> <chr>
1 C-01 COKE NYC
2 C-02 BURGER Chicago, Detroit
3 C-03 CHICKEN, FISH LA, San Fran
Используя функцию любимого режима SO (хотя вы можете использовать любую):
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
В базе R
aggregate(. ~ Customer, lapply(Cus,as.character), Mode)
# Customer Product Store
# 1 C-01 COKE NYC
# 2 C-02 BURGER Chicago
# 3 C-03 CHICKEN LA
с помощью dplyr
library(dplyr)
Cus %>%
group_by(Customer) %>%
summarise_all(Mode)
# # A tibble: 3 x 3
# Customer Product Store
# <fctr> <fctr> <fctr>
# 1 C-01 COKE NYC
# 2 C-02 BURGER Chicago
# 3 C-03 CHICKEN LA
Если у вас много столбцов, и вы хотите узнать максимальное вхождение во всех столбцах, которые вы можете использовать gather
конвертировать данные в длинный формат, count
вхождение для каждого столбца, group_by
Customer
и столбец и сохранить только строки с максимальным количеством, а затем spread
это обратно в широкий формат.
library(tidyverse)
Cus %>%
gather(key, value, -Customer) %>%
count(Customer, key, value) %>%
group_by(Customer, key) %>%
slice(which.max(n)) %>%
ungroup() %>%
spread(key, value) %>%
select(-n)
# Customer Product Store
# <fct> <chr> <chr>
#1 C-01 COKE NYC
#2 C-02 BURGER Chicago
#3 C-03 CHICKEN LA
РЕДАКТИРОВАТЬ
В случае связей, если мы хотим случайным образом выбрать связи, мы можем filter
все max
значения, а затем использовать sample_n
Функция для выбора случайных строк.
Cus %>%
gather(key, value, -Customer) %>%
count(Customer, key, value) %>%
group_by(Customer, key) %>%
filter(n == max(n)) %>%
sample_n(1) %>%
ungroup() %>%
spread(key, value) %>%
select(-n)
# Customer Product Store
# <fct> <chr> <chr>
#1 C-01 COKE NYC
#2 C-02 BURGER Chicago
#3 C-03 FISH San Fran