【发布时间】:2020-03-31 09:02:14
【问题描述】:
我正在寻找一种方法来尽可能高效地完成以下工作,因为我正在处理大型数据集(总共约 700 万行)。 dplyr 与 data.table 比较会非常有帮助。对于一年中的任何一天,我都想知道给定供应商的库存量。我们知道一年中的第一天有多少库存,这是根据库存是移动from 还是to 另一个供应商来创建滚动总和的问题。每行代表一个正在移动的股票。如果有一个NA,这只是意味着有一个外部移动from 或to 并且以相同的方式处理。但是,库存不能低于 0(请参阅下面的供应商a),如果任何供应商发生这种情况,累积总和必须设置为零,并且总和继续。我认为宽幅解决方案在这里没有意义,因为我有超过 100000 家供应商。
小例子:
library(tidyverse)
library(data.table)
set.seed(100)
df <- data.frame(date = sample(seq.Date(from = as.Date("01/01/2018", "%d/%m/%Y"),
to=as.Date("30/01/2018", "%d/%m/%Y"), by = "day"), 20, replace = TRUE),
from = sample(letters[c(1:4, 12)], 20, replace = TRUE),
to = sample(letters[c(1:4, 14, 20)], 20, replace = TRUE), stringsAsFactors = FALSE) %>%
dplyr::arrange(date)
df[14, 2] <- NA
df[10, 3] <- NA
df[5, 3] <- NA
df[6, 2] <- NA
df
# date from to
# 1 2018-01-02 c t
# 2 2018-01-04 l c
# 3 2018-01-06 d n
# 4 2018-01-06 d t
# 5 2018-01-06 a <NA>
# 6 2018-01-07 <NA> d
# 7 2018-01-07 b t
# 8 2018-01-10 b t
# 9 2018-01-11 l n
# 10 2018-01-12 c <NA>
# 11 2018-01-14 b t
# 12 2018-01-16 c a
# 13 2018-01-19 c n
# 14 2018-01-22 <NA> a
# 15 2018-01-23 l t
# 16 2018-01-23 d a
# 17 2018-01-23 c a
# 18 2018-01-23 l c
# 19 2018-01-25 b d
# 20 2018-01-26 a c
以及所有供应商一年中第一天的基准库存计数:
base_line <- data.frame(supplier =c("l", "b", "d", "c", "a", "n", "t"),
count = c(10, 20, 12, 5, 0, 2, 10))
base_line
# supplier count
# 1 l 10
# 2 b 20
# 3 d 12
# 4 c 5
# 5 a 0
# 6 n 2
# 7 t 10
期望产量 (每天的库存数量):
date from to cumsum_var supplier
1 2018-01-02 c t 11 t
2 2018-01-06 d t 12 t
3 2018-01-07 b t 13 t
4 2018-01-10 b t 14 t
5 2018-01-14 b t 15 t
6 2018-01-23 l t 16 t
7 2018-01-06 d n 3 n
8 2018-01-11 l n 4 n
9 2018-01-19 c n 5 n
10 2018-01-06 a <NA> 0 a note 0, not -1
11 2018-01-16 c a 1 a
12 2018-01-22 <NA> a 2 a
13 2018-01-23 d a 3 a
14 2018-01-23 c a 4 a
15 2018-01-26 a c 3 a
16 2018-01-06 d n 11 d
17 2018-01-06 d t 10 d
18 2018-01-07 <NA> d 11 d
19 2018-01-23 d a 10 d
20 2018-01-25 b d 11 d
21 2018-01-02 c t 4 c
22 2018-01-04 l c 5 c
23 2018-01-12 c <NA> 4 c
24 2018-01-16 c a 3 c
25 2018-01-19 c n 2 c
26 2018-01-23 c a 1 c
27 2018-01-23 l c 2 c
28 2018-01-26 a c 3 c
29 2018-01-07 b t 19 b
30 2018-01-10 b t 18 b
31 2018-01-14 b t 17 b
32 2018-01-25 b d 16 b
33 2018-01-04 l c 9 l
34 2018-01-11 l n 8 l
35 2018-01-23 l t 7 l
36 2018-01-23 l c 6 l
我的方法是 filter 基于供应商的两个数据集,执行 cumsum 然后在最后的列表中完全合并,但不包含库存计数可以的警告' t 低于 0(请参阅我的输出中 a 的问题)。
base_line2 <- data.frame(date = rep(as.Date("31/12/2017", "%d/%m/%Y"), 7),
from = c("l", "b", "d", "c", "a", "n", "t"),
from_new = c(10, 20, 12, 5, 0, 2, 10), stringsAsFactors = FALSE)
#get all suppliers (in real dataset >100000)
vars2 <- c("l", "b", "d", "c", "a", "n", "t")
#function
my_fun <- function(x) {
df %>%
filter_at(vars(from, to), any_vars(. == {{x}})) %>%
mutate(from_new = ifelse(from == {{x}}, -1, 0),
to_new = ifelse(to == {{x}}, 1, 0)) %>%
bind_rows({base_line2 %>% filter(from == {{x}})}) %>%
dplyr::arrange(date) %>%
mutate(count_test = rowSums(select(., from_new, to_new), na.rm = T),
cumsum_var = cumsum(count_test))
}
#use function over list
tmp <- lapply(vars2, my_fun)
output = rbindlist(tmp)
output
output %>%
filter(date > as.Date("2017-12-31"))
# date from to from_new to_new count_test cumsum_var
# 1 2018-01-04 l c -1 0 -1 9
# 2 2018-01-11 l n -1 0 -1 8
# 3 2018-01-23 l t -1 0 -1 7
# 4 2018-01-23 l c -1 0 -1 6
# 5 2018-01-07 b t -1 0 -1 19
# 6 2018-01-10 b t -1 0 -1 18
# 7 2018-01-14 b t -1 0 -1 17
# 8 2018-01-25 b d -1 0 -1 16
# 9 2018-01-06 d n -1 0 -1 11
# 10 2018-01-06 d t -1 0 -1 10
# 11 2018-01-07 <NA> d NA 1 1 11
# 12 2018-01-23 d a -1 0 -1 10
# 13 2018-01-25 b d 0 1 1 11
# 14 2018-01-02 c t -1 0 -1 4
# 15 2018-01-04 l c 0 1 1 5
# 16 2018-01-12 c <NA> -1 NA -1 4
# 17 2018-01-16 c a -1 0 -1 3
# 18 2018-01-19 c n -1 0 -1 2
# 19 2018-01-23 c a -1 0 -1 1
# 20 2018-01-23 l c 0 1 1 2
# 21 2018-01-26 a c 0 1 1 3
# 22 2018-01-06 a <NA> -1 NA -1 -1
# 23 2018-01-16 c a 0 1 1 0
# 24 2018-01-22 <NA> a NA 1 1 1
# 25 2018-01-23 d a 0 1 1 2
# 26 2018-01-23 c a 0 1 1 3
# 27 2018-01-26 a c -1 0 -1 2
# 28 2018-01-06 d n 0 1 1 3
# 29 2018-01-11 l n 0 1 1 4
# 30 2018-01-19 c n 0 1 1 5
# 31 2018-01-02 c t 0 1 1 11
# 32 2018-01-06 d t 0 1 1 12
# 33 2018-01-07 b t 0 1 1 13
# 34 2018-01-10 b t 0 1 1 14
# 35 2018-01-14 b t 0 1 1 15
# 36 2018-01-23 l t 0 1 1 16
我认为这里的data.table 方法可能会提高效率或完全更好的dplyr 方法?有没有人建议有效地将库存保持在 0 或以上?
谢谢
【问题讨论】:
-
对不起,好地方,只是缺少
ls,现在更新,ls 现在在底部 -
注意供应商
ls 在我的“期望输出”的底部,但在我自己的方法输出的顶部。只要将它们组合在一起,最终输出中的供应商顺序就无关紧要!
标签: r performance dplyr data.table cumsum