根据两个表之间的日期逻辑计算列

时间:2019-07-12 08:03:59

标签: r dplyr

我想根据表之间的逻辑来计算一列。让我解释一下,给出一个具有以下结构的data.frame:

Transaction - Start - End - Quantity - Area
(Number) - (Date) - (Date) - (Number) - (Number)

StartEnd确定TransactionArea中已有多长时间了。我想计算每天 的每个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

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 。 最后,您要做的就是保留日历数据框中存在的日期。

希望这会有所帮助!