【问题标题】:Historising project data历史项目数据
【发布时间】:2022-01-18 21:14:08
【问题描述】:

我经常遇到这样的问题,即我有描述状态(在本例中为项目阶段)的确切变化的数据,我想记录这些数据。

这意味着我希望能够在过去的某个时间描述哪个项目处于哪个阶段。

让我们使用这个测试数据:

library(data.table)
library(lubridate)

df = structure(list(Project = c("A", "A", "B", "B", "B", "B", "C", 
                            "C", "C", "D", "D"), Date = structure(c(18659, 18748, 18687, 
                                                                    18718, 18748, 18871, 18718, 18718, 18779, 18659, 18840), class = "Date"), 
                Phase = c("Init", "P2O", "Init", "P2O", "Build", "Doc", "Init", 
                          "P2O", "Build", "Init", "P2O")), row.names = c(NA, -11L), class = c("data.table", 
                                                                                              "data.frame"))

df[, Date:=ceiling_date(as.Date(Date, format="%d.%m.%Y"), "month")]

它们看起来像:

    Project       Date Phase
Project       Date Phase
 1:       A 2021-03-01  Init
 2:       A 2021-06-01   P2O
 3:       B 2021-04-01  Init
 4:       B 2021-05-01   P2O
 5:       B 2021-06-01 Build
 6:       B 2021-10-01   Doc
 7:       C 2021-05-01  Init
 8:       C 2021-05-01   P2O
 9:       C 2021-07-01 Build
10:       D 2021-03-01  Init
11:       D 2021-09-01   P2O

现在我想创建一个表格,其中每个阶段都有一个列,每个日期有一个行。

我试过了:

> dcast(df, Date~Phase, fun=length)[order(Date)]
         Date Build Doc Init P2O
1: 2021-03-01     0   0    2   0
2: 2021-04-01     0   0    1   0
3: 2021-05-01     0   0    1   2
4: 2021-06-01     1   0    0   1
5: 2021-07-01     1   0    0   0
6: 2021-09-01     0   0    0   1
7: 2021-10-01     0   1    0   0

但这是一个大错误。 让我们看看A项目。

Project       Date Phase
 1:       A 2021-03-01  Init
 2:       A 2021-06-01   P2O

项目 A 于 2021 年 3 月 1 日进入“初始化”阶段,2021 年 6 月 1 日进入“P2O”阶段。在当前的逻辑中,这看起来像:

         Date Build Doc Init P2O
1: 2021-03-01     0   0    1   0
4: 2021-06-01     0   0    0   1

但这是错误的。在 3 月和 6 月之间,该项目仍处于 Init 阶段,因此正确的应该是这样的:

         Date Build Doc Init P2O
1: 2021-03-01     0   0    1   0
2: 2021-04-01     0   0    1   0
3: 2021-05-01     0   0    1   0
4: 2021-06-01     0   0    0   1

有人知道我该如何解决这个问题吗?

【问题讨论】:

    标签: r data.table lubridate


    【解决方案1】:

    也许是这个?

    dfwide <- dcast(df, Project + Date ~ Phase, fun = length)
    merge(
      dfwide,
      dfwide[, .(Date = seq(min(Date), max(Date), by = "month")), by = .(Project)],
      by = c("Project", "Date"), all = TRUE
    )[order(Date),
      ][, setNames(nafill(.SD, type = "locf"), names(.SD)), by = .(Project)]
    #     Project       Date Build   Doc  Init   P2O
    #      <char>     <Date> <int> <int> <int> <int>
    #  1:       A 2021-03-01     0     0     1     0
    #  2:       A 2021-04-01     0     0     1     0
    #  3:       A 2021-05-01     0     0     1     0
    #  4:       A 2021-06-01     0     0     0     1
    #  5:       D 2021-03-01     0     0     1     0
    #  6:       D 2021-04-01     0     0     1     0
    #  7:       D 2021-05-01     0     0     1     0
    #  8:       D 2021-06-01     0     0     1     0
    #  9:       D 2021-07-01     0     0     1     0
    # 10:       D 2021-08-01     0     0     1     0
    # 11:       D 2021-09-01     0     0     0     1
    # 12:       B 2021-04-01     0     0     1     0
    # 13:       B 2021-05-01     0     0     0     1
    # 14:       B 2021-06-01     1     0     0     0
    # 15:       B 2021-07-01     1     0     0     0
    # 16:       B 2021-08-01     1     0     0     0
    # 17:       B 2021-09-01     1     0     0     0
    # 18:       B 2021-10-01     0     1     0     0
    # 19:       C 2021-05-01     0     0     1     1
    # 20:       C 2021-06-01     0     0     1     1
    # 21:       C 2021-07-01     1     0     0     0
    #     Project       Date Build   Doc  Init   P2O
    

    没有文字 merge 也一样(尽管我们只是使用 data.table-left-join 代替)

    dfwide[
      dfwide[, .(Date = unique(c(seq(min(Date), max(Date), by = "month"), max(Date)))), by = .(Project)],
      on = .(Project, Date)][order(Date),
      ][, setNames(nafill(.SD, type = "locf"), names(.SD)), by = .(Project)]
    

    unique(c(..., max(Date))) 的使用是为了确保始终使用/保留最大日期;如果seq(.) 中的任何一个未达到最大日期而未登陆,则可能不包括最大日期。当我们使用merge(.., all=TRUE) 时,这不是问题,因为无论如何它都会被保留,但是使用左连接时,它可能会被省略。 (不过,不在这个数据中。我只是在防守。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多