Масштабируемый способ агрегирования данных по периоду времени с вложенными переменными - PullRequest
0 голосов
/ 13 ноября 2018

Обзор

У меня есть фиктивный набор данных с 20 транзакциями.Каждая транзакция содержит:

  1. Customer_ID
  2. Дата (дата покупки)
  3. Канал (канал покупки, DIRECT или RETAIL)
  4. Сумма (сумма в долларах)транзакции)

В этих фиктивных данных содержится пять различных идентификаторов Customer_ID.

Все даты в этом фиктивном интервале данных с 01 января 2010 года по 18 октября 2018 года.

Яопределение двух периодов времени на основе константы Promo_Date, где Promo_Date = 01OCT2018:

  • T1 = Дата
  • T2 = Дата> = Promo_Date

Я хотел бы «свести» эти данные к одной записи для каждого Customer_ID, где рассматриваются канал (DIRECT или RETAIL) и период времени (T1 или T2).Желаемые агрегированные данные содержат следующую структуру:

  1. Customer_ID
  2. DIRECT_T1_Last_Date (Дата последней прямой покупки в T1; нет данных, если ее нет)
  3. DIRECT_T1_Orders (Количество прямых покупокв T1)
  4. DIRECT_T1_Amount (Сумма суммы прямых покупок в T1)
  5. RETAIL_T1_Last_Date (Дата последней розничной покупки в T1; нет данных, если ее нет)
  6. RETAIL_T1_Orders (Number of Retailпокупки в T1)
  7. RETAIL_T1_Amount (Сумма розничных покупок в T1)
  8. T2_Amount (сумма в Т2 независимо от канала)

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

Я экспериментировал с пакетами reshape2 и tidyr и убежден, что один (или оба) из них могут предоставить более элегантное решение, но я просто не могу его решить.

Создание фиктивных данных

Customer_ID <- c(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5)

Date <- c('2018-07-17', '2018-07-25', '2018-10-04', '2018-07-29', '2018-08-15', 
          '2018-09-03', '2018-09-30', '2018-10-01', '2018-02-16', '2018-03-27',
          '2018-04-30', '2018-10-18', '2018-07-07', '2018-08-24', '2018-01-01', 
          '2018-01-23', '2018-02-08', '2018-02-27', '2018-03-31', '2018-07-20')

Channel <- c('DIRECT', 'RETAIL', 'DIRECT', 'DIRECT', 'RETAIL', 'DIRECT', 'DIRECT', 'DIRECT', 'DIRECT', 'DIRECT', 
             'DIRECT', 'RETAIL', 'DIRECT', 'DIRECT', 'RETAIL', 'RETAIL', 'RETAIL', 'DIRECT', 'DIRECT', 'DIRECT')

Amount <- c(118.70,  78.79, 89.99,  69.42, 116.62, 127.11,  86.85,  90.15, 109.37, 121.31,
            125.45, 117.89, 90.51, 123.02, 127.66, 120.89, 122.52, 102.76,  72.18,  92.88)

orders <- data.frame(cbind(data.frame(Customer_ID), 
                           data.frame(Date), 
                           data.frame(Channel),   
                           data.frame(Amount)))

rm(Customer_ID, Date, Channel, Amount)

orders <- orders %>%
  mutate(Date        = as.Date(Date, "%Y-%m-%d"),
         Channel     = as.character(Channel)
         ) %>%
  arrange(Customer_ID, Date, Channel, Amount)

Фиктивные данные

   Customer_ID       Date Channel Amount
1            1 2018-07-17  DIRECT 118.70
2            1 2018-07-25  RETAIL  78.79
3            1 2018-10-04  DIRECT  89.99
4            2 2018-07-29  DIRECT  69.42
5            2 2018-08-15  RETAIL 116.62
6            2 2018-09-03  DIRECT 127.11
7            2 2018-09-30  DIRECT  86.85
8            2 2018-10-01  DIRECT  90.15
9            3 2018-02-16  DIRECT 109.37
10           3 2018-03-27  DIRECT 121.31
11           3 2018-04-30  DIRECT 125.45
12           3 2018-10-18  RETAIL 117.89
13           4 2018-07-07  DIRECT  90.51
14           4 2018-08-24  DIRECT 123.02
15           5 2018-01-01  RETAIL 127.66
16           5 2018-01-23  RETAIL 120.89
17           5 2018-02-08  RETAIL 122.52
18           5 2018-02-27  DIRECT 102.76
19           5 2018-03-31  DIRECT  72.18
20           5 2018-07-20  DIRECT  92.88

Определение константы Promo_Date

Promo_Date <- as.Date("2018-10-01", "%Y-%m-%d")

My Long, решение для грубой силы

DIRECT_T1 <- orders %>%
  filter(Channel == 'DIRECT' & Date < Promo_Date) %>%
  group_by(Customer_ID) %>%
  summarise(DIRECT_T1_Last_Date = max(Date),
            DIRECT_T1_Orders = n(),
            DIRECT_T1_Amount = sum(Amount))

RETAIL_T1 <- orders %>%
      filter(Channel == 'RETAIL' & Date < Promo_Date) %>%
      group_by(Customer_ID) %>%
      summarise(RETAIL_T1_Last_Date = max(Date),
                RETAIL_T1_Orders = n(),
                RETAIL_T1_Amount = sum(Amount))

T2 <- orders %>%
  filter(Date >= Promo_Date) %>%
  group_by(Customer_ID) %>%
  summarise(T2_Amount = sum(Amount))

Flat_Orders_Long_Way <- full_join(DIRECT_T1, RETAIL_T1, by = "Customer_ID") %>%
  full_join(., T2, by = "Customer_ID") %>%
  mutate(DIRECT_T1_Orders = ifelse(is.na(DIRECT_T1_Orders) == TRUE, 0, DIRECT_T1_Orders),
         DIRECT_T1_Amount = ifelse(is.na(DIRECT_T1_Amount) == TRUE, 0, DIRECT_T1_Amount),
         RETAIL_T1_Orders = ifelse(is.na(RETAIL_T1_Orders) == TRUE, 0, RETAIL_T1_Orders),
         RETAIL_T1_Amount = ifelse(is.na(RETAIL_T1_Amount) == TRUE, 0, RETAIL_T1_Amount),
         T2_Amount        = ifelse(is.na(T2_Amount) == TRUE, 0, T2_Amount)) %>%
  arrange(Customer_ID)

Flat_Orders_Long_Way <- data.frame(Flat_Orders_Long_Way)

rm(DIRECT_T1, RETAIL_T1, T2)

Желаемые результаты(имена переменных сокращены для этого поста)

compact_output <- Flat_Orders_Long_Way %>%
      rename(ID = Customer_ID,
             Direct_LDATE = DIRECT_T1_Last_Date,
             Direct_Orders = DIRECT_T1_Orders,
             Direct_Amount = DIRECT_T1_Amount,
             Retail_LDATE = RETAIL_T1_Last_Date,
             Retail_Orders = RETAIL_T1_Orders,
             Retail_Amount = RETAIL_T1_Amount)

 print(compact_output)

      ID Direct_LDATE Direct_Orders Direct_Amount Retail_LDATE Retail_Orders Retail_Amount T2_Amount
    1  1   2018-07-17             1        118.70   2018-07-25             1         78.79     89.99
    2  2   2018-09-30             3        283.38   2018-08-15             1        116.62     90.15
    3  3   2018-04-30             3        356.13         <NA>             0          0.00    117.89
    4  4   2018-08-24             2        213.53         <NA>             0          0.00      0.00
    5  5   2018-07-20             3        267.82   2018-02-08             3        371.07      0.00

Закрытие

Заранее спасибо за вашу помощь!

...