Существует ли функция dplyr для определения наиболее часто встречающегося категориального значения в группе? - PullRequest
0 голосов
/ 22 января 2019

Я хочу объединить данные транзакции клиента в одну строку для каждого клиента, используя dplyr. Для непрерывных переменных это просто - используйте сумму / среднее и т. Д. Для категориальных переменных я хотел бы выбрать «Режим», то есть наиболее часто встречающееся значение в группе, и сделать это в нескольких столбцах, например ::100100

Например взять таблицу 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 ]

0 голосов
/ 22 января 2019

Использование Функция любимого режима 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
0 голосов
/ 22 января 2019

Если у вас много столбцов и вы хотите узнать максимальное вхождение во всех столбцах, вы можете использовать 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   

EDIT

В случае связей, если мы хотим случайным образом выбрать связи, мы можем 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
0 голосов
/ 22 января 2019

В моем решении, если есть более одного наиболее часто встречающегося значения, все представлены:

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  
0 голосов
/ 22 января 2019

Как насчет этого?

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))
...