我想根据表之间的逻辑来计算一列。让我解释一下,给出一个具有以下结构的data.frame:
Transaction - Start - End - Quantity - Area
(Number) - (Date) - (Date) - (Number) - (Number)
Start
和End
确定Transaction
在Area
中已有多长时间了。我想计算每天 的每个Area
中的 stock 。
什么是存货? 遵循此逻辑的数量总和:
Start <= day AND End >= day
OR
Start <= day AND End == NULL
星期几?日历的每一天。 (因此,表之间的逻辑。)
如何用R计算每个区域每天的存量?示例数据:
calendar <- as.data.frame(seq.Date(as.Date("2019-01-01"), as.Date("2019-01-10"), 1))
colnames(calendar) <- c("Date")
> head(calendar)
Date
1 2019-01-01
2 2019-01-02
3 2019-01-03
4 2019-01-04
5 2019-01-05
6 2019-01-06
Transaction <- c(299784, 299785, 301913, 302840, 305722, 285874, 285875, 312587, 326842, 328521)
Start <- as.Date(c("2019-01-01", "2019-01-01", "2019-01-02", "2019-01-02", "2019-01-03", "2019-01-01", "2019-01-01", "2019-01-02", "2019-01-02", "2019-01-03"))
End <- as.Date(c("2019-01-05", "2019-01-04", "2019-01-06", "2019-01-03", "NULL", "2019-01-05", "2019-01-04", "2019-01-06", "2019-01-03", "NULL"))
Quantity <- c(1,1,1,1,1,1,1,1,1,1)
Area <- c(7065, 7065, 7065, 7065, 7065, 6098, 6098, 6098, 6098, 6098)
df <- data.frame(Transaction, Start, End, Quantity, Area)
> df
Transaction Start End Quantity Area
1 299784 2019-01-01 2019-01-05 1 7065
2 299785 2019-01-01 2019-01-04 1 7065
3 301913 2019-01-02 2019-01-06 1 7065
4 302840 2019-01-02 2019-01-03 1 7065
5 305722 2019-01-03 <NA> 1 7065
6 285874 2019-01-01 2019-01-05 1 6098
7 285875 2019-01-01 2019-01-04 1 6098
8 312587 2019-01-02 2019-01-06 1 6098
9 326842 2019-01-02 2019-01-03 1 6098
10 328521 2019-01-03 <NA> 1 6098
每天的库存为:
Date Area Stock
1 2019-01-01 7065 2
2 2019-01-02 7065 4
3 2019-01-03 7065 5
4 2019-01-04 7065 4
5 2019-01-05 7065 3
6 2019-01-06 7065 2
7 2019-01-07 7065 1
8 2019-01-08 7065 1
9 2019-01-09 7065 1
10 2019-01-10 7065 1
11 2019-01-01 6098 2
12 2019-01-02 6098 4
13 2019-01-03 6098 5
14 2019-01-04 6098 4
15 2019-01-05 6098 3
16 2019-01-06 6098 2
17 2019-01-07 6098 1
18 2019-01-08 6098 1
19 2019-01-09 6098 1
20 2019-01-10 6098 1
或:
Date 7065 6098
1 2019-01-01 2 2
2 2019-01-02 4 4
3 2019-01-03 5 5
4 2019-01-04 4 4
5 2019-01-05 3 3
6 2019-01-06 1 1
7 2019-01-07 1 1
8 2019-01-08 1 1
9 2019-01-09 1 1
10 2019-01-10 1 1
答案 0 :(得分:1)
Edit3 :
此方法具有以下原则:
您需要每天计算您的库存,但是有几天的范围。因此,我们必须将天数范围转换为单日,同时保留其余数据,然后按以下方式进行分组和计数。
但是,您这里有“烦人”的 NA ,因此我们必须首先摆脱这些烦恼。由于当结束日期为 NA 时,您仍想将交易视为正在进行中,因此首先将 NA 转换为日历数据框的最大日期,因此以后我们将其每天最多计数为1:
df$End <- as.Date(ifelse(is.na(df$End), max(calendar$Date), df$End), origin = "1970-01-01")
> df
Transaction Start End Quantity Area
1 299784 2019-01-01 2019-01-05 1 7065
2 299785 2019-01-01 2019-01-04 1 7065
3 301913 2019-01-02 2019-01-06 1 7065
4 302840 2019-01-02 2019-01-03 1 7065
5 305722 2019-01-03 2019-01-10 1 7065
6 285874 2019-01-01 2019-01-05 1 6098
7 285875 2019-01-01 2019-01-04 1 6098
8 312587 2019-01-02 2019-01-06 1 6098
9 326842 2019-01-02 2019-01-03 1 6098
10 328521 2019-01-03 2019-01-10 1 6098
此后,我们需要在开始-结束日期之间生成缺少的日期。为此,我们可以按照以下方式使用MKR's example中的complete
中的tidyr
:
library(tidyr)
nf <- df %>% group_by(row_number()) %>% complete(Start=seq.Date(max(Start), max(End), by='day')) %>% fill(Transaction, End, Quantity, Area)
我们的新数据框 nf 现在具有一个新的开始日期,该日期对应于日期范围内每个交易/数量/区域组合唯一。
> nf
# A tibble: 48 x 6
# Groups: row_number() [10]
`row_number()` Start Transaction End Quantity Area
<int> <date> <dbl> <date> <dbl> <dbl>
1 1 2019-01-01 299784 2019-01-05 1 7065
2 1 2019-01-02 299784 2019-01-05 1 7065
3 1 2019-01-03 299784 2019-01-05 1 7065
4 1 2019-01-04 299784 2019-01-05 1 7065
5 1 2019-01-05 299784 2019-01-05 1 7065
6 2 2019-01-01 299785 2019-01-04 1 7065
7 2 2019-01-02 299785 2019-01-04 1 7065
8 2 2019-01-03 299785 2019-01-04 1 7065
9 2 2019-01-04 299785 2019-01-04 1 7065
10 3 2019-01-02 301913 2019-01-06 1 7065
# … with 38 more rows
然后我们可以按照我之前已经提出的建议进行操作
zf <- nf %>% group_by(Start, Area) %>% tally(Quantity)
> zf
# A tibble: 20 x 3
# Groups: Start [10]
Start Area n
<date> <dbl> <dbl>
1 2019-01-01 6098 2
2 2019-01-01 7065 2
3 2019-01-02 6098 4
4 2019-01-02 7065 4
5 2019-01-03 6098 5
6 2019-01-03 7065 5
7 2019-01-04 6098 4
8 2019-01-04 7065 4
9 2019-01-05 6098 3
10 2019-01-05 7065 3
11 2019-01-06 6098 2
12 2019-01-06 7065 2
13 2019-01-07 6098 1
14 2019-01-07 7065 1
15 2019-01-08 6098 1
16 2019-01-08 7065 1
17 2019-01-09 6098 1
18 2019-01-09 7065 1
19 2019-01-10 6098 1
20 2019-01-10 7065 1
我们在这里正在做的是要求dplyr
使用开始(最终是该日期的唯一交易)和区域变量即可得出总数。然后,您可以将其存储在新表中,在本示例中为 zf 。
编辑1:
要最终获得所需的表格格式,您可以从spread
包中运行tidyr
zf <- zf %>% spread(Area, n)
>zf
# A tibble: 10 x 3
# Groups: Start [10]
Start `6098` `7065`
<date> <dbl> <dbl>
1 2019-01-01 2 2
2 2019-01-02 4 4
3 2019-01-03 5 5
4 2019-01-04 4 4
5 2019-01-05 3 3
6 2019-01-06 2 2
7 2019-01-07 1 1
8 2019-01-08 1 1
9 2019-01-09 1 1
10 2019-01-10 1 1
这会根据您的计数( n )在新列上分散列 Area 。 最后,您要做的就是保留日历数据框中存在的日期。
希望这会有所帮助!