【问题标题】:Calculate column based on date logic between two tables根据两个表之间的日期逻辑计算列
【发布时间】:2019-11-21 23:16:13
【问题描述】:

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

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

Start 和End 确定Transaction 在Area 中的使用时间。我想为每一天计算每个Area中的库存。

什么是库存? 遵循此逻辑的 Quantity 总和:

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

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    编辑3:

    这种方法有以下原理:
    您需要每天计算您的库存,但您有一个天数范围。因此,我们必须将天数范围转换为单天数,同时保留其余数据,然后按如下方式分组和计数。
    但是你有'烦人的' NAs 在那里,因此我们必须首先摆脱那些。由于当 End 日期为 NA 时,您仍希望将交易视为正在进行中,首先我将 将 NAs 转换为您的日历数据框的最大日期,因此我们稍后会将它们计算为每天 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 使用tidyr 中的complete,方式如下:

    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 使用 Start(最终成为我们在该日期的唯一交易)和 Area 变量给你总数量。然后,您可以将其存储在一个新表中,在本例中为 zf。

    编辑1: 要以您请求的表格格式结束,您可以从 tidyr 包中运行 spread

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

    希望这会有所帮助!

    【讨论】:

    • 您好,感谢您的回答。结束日期是相关的。例如,1 月 8 日,Area 7065 的库存为 1,因为有一笔交易未完成(“df”的第 5 行),这意味着 2018-01-03
    • 我现在明白你的意思了——我当时误解了复杂性。我会回复你的。
    • 问题:在你的日历上你有 2019 年的数据框你有 2019 年和你的 df 你有 2018 年。这是一个错字吗?否则所有的日子都将大于您的 df$End。我目前正在编辑我的回复以反映您的 cmets。
    • 检查我编辑的回复,让我知道这是否是你要找的。​​span>
    • 很高兴它有帮助!顺便说一下,我在分组中犯了一个错误:您需要使用tally(Quantity) 而不是count(),因为我们想要数量的总和而不仅仅是出现的日期数。我做了最后的编辑。祝你好运,继续努力!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    相关资源
    最近更新 更多