альтернатива data.table для медленных функций group_by () и case_when () - PullRequest
1 голос
/ 13 марта 2019

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

Не могли бы вы указать мне решение?До сих пор у меня не было контактов с таблицей data.table ...

# generate data
id <- round(rnorm(3000, mean = 5000, 400),0)
date <- seq.Date(as.Date("2018-01-01"), as.Date("2018-12-31"), "day")
date <- sample(date, length(id), replace = TRUE)
indicator <-  rbinom(length(id), 1, 0.5)

df <- data.frame(id, date, indicator)
df$id <- as.factor(df$id)

# Does the first Order contain X?
df <- df %>% group_by(id) %>% mutate(First_Order_contains_x = case_when(
  date == min(date) & indicator == "1" ~ 1,
  TRUE ~ 0
)) %>% ungroup() 

# If first order > 1 ==> all orders get 1 // 
df <- df %>% group_by(id) %>% mutate(Customer_type = case_when(
  sum(First_Order_contains_x) > 0 ~ "Customer with X in first order",
  TRUE ~ "Customer without x in first order"
)) %>% ungroup() 

Ответы [ 3 ]

2 голосов
/ 13 марта 2019

Другой способ:

library(data.table)
DT = data.table(df[, 1:3])

lookupDT = DT[, .(date = min(date)), by=id]
lookupDT[, fx := DT[copy(.SD), on=.(id, date), max(indicator), by=.EACHI]$V1]

DT[, v := "Customer without x in first order"]
DT[lookupDT[fx == 1L], on=.(id), v := "Customer with X in first order"]

# check results
fsetequal(DT[, .(id, v)], data.table(id = df$id, v = df$Customer_type))
# [1] TRUE

Если вы хотите больше улучшений скорости, возможно, посмотрите: ?IDate.

Требуется copy на .SD из-за anоткрытый выпуск .

0 голосов
/ 14 марта 2019

Другой data.table подход. Сначала отсортируйте данные так, чтобы первая дата была самой ранней, а затем мы можем использовать первый индикатор для проверки условия. Затем преобразуйте логическое в целое число (FALSE -> 1 и TRUE -> 2) и отобразите в нужный вывод, используя вектор символов.

library(data.table)
setDT(df)
setorder(df, id, date)
map <- c("Customer without x in first order", "Customer with X in first order")
df[, idx := 1L+any(indicator[1L]==1L), by=.(id)][,
    First_Order_contains_x := map[idx]]

Если важен исходный заказ, мы можем сохранить исходный заказ, используя df[, rn := .I], и, наконец, setorder(df, rn).

данные:

set.seed(0L)
id <- round(rnorm(3000, mean = 5000, 5),0)
date <- seq.Date(as.Date("2018-01-01"), as.Date("2018-12-31"), "day")
date <- sample(date, length(id), replace = TRUE)
indicator <-  rbinom(length(id), 1, 0.5)

df <- data.frame(id, date, indicator)
df$id <- as.factor(df$id)
0 голосов
/ 13 марта 2019

Вот как вы можете улучшить свой существующий код, используя dplyr более эффективно:

lookup = data.frame(First_Order_contains_x = c(TRUE, FALSE), 
                    Customer_Type = c("Customer with X in first order", 
                                      "Customer without x in first order"))

df %>% 
  group_by(id) %>% 
  mutate(First_Order_contains_x = any(as.integer(date == min(date) & indicator == 1))) %>% 
  ungroup() %>% 
  left_join(lookup, by = "First_Order_contains_x")

# A tibble: 3,000 x 5
   id    date       indicator First_Order_contains_x Customer_Type                    
   <fct> <date>         <dbl> <lgl>                  <fct>                            
 1 5056  2018-03-10         1 TRUE                   Customer with X in first order   
 2 5291  2018-12-28         0 FALSE                  Customer without x in first order
 3 5173  2018-04-19         0 FALSE                  Customer without x in first order
 4 5159  2018-11-13         0 TRUE                   Customer with X in first order   
 5 5252  2018-05-30         0 TRUE                   Customer with X in first order   
 6 5200  2018-01-20         0 FALSE                  Customer without x in first order
 7 4578  2018-12-18         1 FALSE                  Customer without x in first order
 8 5308  2018-03-24         1 FALSE                  Customer without x in first order
 9 5234  2018-05-29         1 TRUE                   Customer with X in first order   
10 5760  2018-06-12         1 TRUE                   Customer with X in first order   
# … with 2,990 more rows
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...