data.table用于慢速group_by()和case_when()函数的替代方法
在我的数据中,我有客户ID、订单日期和一个指示器,如果订单包含一种产品类型。 我想给每个客户一个指标,如果他的第一份订单包含这种类型的产品。但是因为我的数据非常大,所以我不能在任何时候使用分组和案例,因为它太慢了。我想通过使用data.table,我可以大大加快速度 你能给我指出一个解决办法吗?到目前为止,我还没有接触过data.tabledata.table用于慢速group_by()和case_when()函数的替代方法,r,dplyr,data.table,R,Dplyr,Data.table,在我的数据中,我有客户ID、订单日期和一个指示器,如果订单包含一种产品类型。 我想给每个客户一个指标,如果他的第一份订单包含这种类型的产品。但是因为我的数据非常大,所以我不能在任何时候使用分组和案例,因为它太慢了。我想通过使用data.table,我可以大大加快速度 你能给我指出一个解决办法吗?到目前为止,我还没有接触过data.table # generate data id <- round(rnorm(3000, mean = 5000, 400),0) date <- seq
# 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()
#生成数据
id 0~“第一批订单中有X的客户”,
TRUE~“第一批订单中没有x的客户”
))%%>%ungroup()
以下是如何更有效地使用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
lookup=data.frame(第一顺序包含x=c(真、假),
客户类型=c(“第一批订单中有X的客户”,
“第一批订单中没有x的客户”))
df%>%
分组依据(id)%>%
mutate(第一个\u顺序\u包含\u x=any(as.integer(date==min(date)&indicator==1))%>%
解组()%>%
左联接(查找方式为=“第一个订单包含x”)
#一个tibble:3000 x 5
id日期指示器第一批订单包含客户类型
15056 2018-03-10第一批订单中有X的真正客户
2 5291 2018-12-28 0第一批订单中没有x的虚假客户
351732018-04-19 0第一批订单中没有x的虚假客户
4 5159 2018-11-13第一批订单中X的真实客户
5 5252 2018-05-30第一批订单中X的真实客户
6 5200 2018-01-20第一批订单中没有x的虚假客户
7 4578 2018-12-18 1第一批订单中没有x的虚假客户
85308 2018-03-24 1第一批订单中没有x的虚假客户
9 5234 2018-05-29第一批订单中有X的1个真正客户
10 5760 2018-06-12第一批订单中有X的1个真正客户
#…还有2990行
另一种方式:
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
由于。另一种
数据。表
方法,需要在.SD
上复制。首先对数据进行排序,使第一个日期是最早的日期,然后我们可以使用第一个指示器来测试条件。然后,将逻辑转换为整数(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]]
谢谢,我改了!当您有多个选择时,您应该使用case\u。这里您只有两个,因此您可以尝试在mutate
中使用第一个\u Order\u contains\u x=as.integer(date==min(date)&indicator==1”)
。谢谢,我完成了这个任务,时间从739秒缩短到139秒。另一个答案的data.table方法甚至更快(19秒),但结果并不相同。
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)