如何用 r data.table 填写数据框中所有可能的列?

How to fill out all possible columns in a dataframe with r data.table?

假设我们从下面的 data 数据帧开始,由下面的代码生成:

> data
  ID Period_1 Period_2 Values State
1  1        1  2020-01      5    X0
2  1        2  2020-02     10    X1
3  1        3  2020-03     15    X0
4  2        1  2020-04      0    X0
5  2        2  2020-05      2    X2
6  2        3  2020-06      4    X0
7  3        1  2020-02      3    X2
8  3        2  2020-03      6    X1
9  3        3  2020-04      9    X0

data <- 
  data.frame(
    ID = c(1,1,1,2,2,2,3,3,3),
    Period_1 = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
    Period_2 = c("2020-01","2020-02","2020-03","2020-04","2020-05","2020-06","2020-02","2020-03","2020-04"),
    Values = c(5, 10, 15, 0, 2, 4, 3, 6, 9),
    State = c("X0","X1","X0","X0","X2","X0", "X2","X1","X0")
  )

我正在尝试学习如何使用 R 包 data.table,并想用它来计算从给定状态(下面代码示例中的状态“X0”)到另一个状态的转换,当从一个周期移动或“过渡”到下一个周期时(在这种情况下,周期测量是“Period_1”)。当 运行 下面的 data.table 代码时,我得到以下结果:

   OutflowState 2 4
1:           X0 0 0
2:           X1 1 0
3:           X2 1 0

Code run:

library(data.table)

dcast(
  setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID]
  [, period_factor := lapply(.SD, factor), .SDcols = "Period_1"]
  [, period_factor := as.numeric(period_factor) + 1],
    OutflowState ~ period_factor, length, 
    value.var = "Values", subset = .(State == "X0"), drop = FALSE
)

此输出是正确的,但我想 (a) 向周期 1 和周期 3 的输出添加列(周期 1 将始终全为 0,周期 3 应在这种情况下显示全 0 data dataframe 因为周期 2 中没有 state = X0;和 (b) 从输出中删除 Period_1 = 4 的列,因为没有周期 = 4,这只是代码中使用的一个技巧以上 as.numeric(period_factor) + 1 以标记下一个过渡期。我该怎么做?

当 运行 下面显示的代码段时,我得到以下临时数据帧,所以一种解决方案是删除 OutflowState = NA 的任何行(消除所有名义周期 4),但我不这样做知道怎么做了。

   ID Period_1 Period_2 Values State OutflowState period_factor
1:  1        1  2020-01      5    X0           X1             2
2:  1        2  2020-02     10    X1           X0             3
3:  1        3  2020-03     15    X0         <NA>             4
4:  2        1  2020-04      0    X0           X2             2
5:  2        2  2020-05      2    X2           X0             3
6:  2        3  2020-06      4    X0         <NA>             4
7:  3        1  2020-02      3    X2           X1             2
8:  3        2  2020-03      6    X1           X0             3
9:  3        3  2020-04      9    X0         <NA>             4

setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID][
  , period_factor := lapply(.SD, factor), .SDcols = "Period_1"][
  , period_factor := as.numeric(period_factor) + 1  
  ]
data

这个问题是 解决转型流入问题的产物。请注意,上面的 data.table 代码允许将时间范围定义为 Period_2 的替代方案,并且可以对值的转换求和而不是对转换进行计数,并且需要维护这些功能。

下图更能说明问题:

dcastdrop = FALSE 将为 period_factor 的每个因子水平创建列,因此您需要列 13 而不是 4 在结果中,我们需要将 period_factor 的级别设置为包括 13 但不包括 4 (并保持 factor class!)。我也简化了 period_factor 的创建,仅当我们将其应用于多个列时才需要 lapply.SDcols

dcast(
  setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID]
  [, period_factor := factor(Period_1 + 1, levels = seq(1, max(Period_1)))],
    OutflowState ~ period_factor, length, 
    value.var = "Values",
    subset = .(State == "X0" ),
    drop = FALSE
)
#    OutflowState 1 2 3
# 1:           X0 0 0 0
# 2:           X1 0 1 0
# 3:           X2 0 1 0

我们可以从 to the question 中获取 state_inflow() 函数并将其转换为 state_outflow() 函数:

state_inflow <- function(mydat, target_state) {
  dcast(
    setDT(mydat)[, Previous_State := shift(State, fill = target_state), by = ID],
    factor(Previous_State) ~ factor(Period_1), length, value.var = "Values",
    subset = .(State == target_state), drop = FALSE
  )
} 

通过互换 StatePrevious_Statedcast() 中的角色 :

state_outflow <- function(mydat, target_state) {
  dcast(
    setDT(mydat)[, Previous_State := shift(State), by = ID],
    factor(State) ~ factor(Period_1), length, value.var = "Values",
    subset = .(Previous_State == target_state), drop = FALSE
  )
}

此外,shift() 函数没有提供任何填充值。所以,每个ID第一期的前一个状态是NA.

调用函数给出预期结果:

state_outflow(data, "X0")
   State 1 2 3
1:    X0 0 0 0
2:    X1 0 1 0
3:    X2 0 1 0

无需调整因子水平。