【问题标题】:Create a time to and time after event variables创建事件变量的时间和时间
【发布时间】:2021-05-03 09:30:24
【问题描述】:

我正在处理如下所示的面板数据:

d <- data.frame(id = c("a", "a", "a", "a", "a", "b", "b", "b", "b", "b", "c", "c", "c", "c", "c"),
                time = c(1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5),
                iz = c(0,1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1))
   id time iz
1   a    1  0
2   a    2  1
3   a    3  1
4   a    4  0
5   a    5  0
6   b    1  0
7   b    2  0
8   b    3  0
9   b    4  0
10  b    5  1
11  c    1  0
12  c    2  0
13  c    3  0
14  c    4  1
15  c    5  1

这里 iz 是事件或治疗的指标 (iz = 1)。我需要的是一个变量,它计算事件前后的时间段或事件的距离。这个变量看起来像这样:

  id time iz nvar
1   a    1  0   -1
2   a    2  1    0
3   a    3  1    0
4   a    4  0    1
5   a    5  0    2
6   b    1  0   -4
7   b    2  0   -3
8   b    3  0   -2
9   b    4  0   -1
10  b    5  1    0
11  c    1  0   -1
12  c    2  0   -2
13  c    3  0   -3
14  c    4  1    0
15  c    5  1    0

我尝试使用herehere 给出的答案,但在我的情况下无法使用。

我非常感谢任何解决此问题的想法。提前感谢您的所有想法和建议。

【问题讨论】:

  • 每个id 是否只有一个事件/治疗?如果不是,并且可能有多个事件,您希望如何在事件之间处理nvar
  • 抱歉没有澄清。理想情况下,此类观察将被视为“后”观察。我在下面尝试了机器人示例,Grothediecks 的回答就是这样做的,而 Wimpels 的回答将它们视为“pre”。

标签: r tidyverse panel-data


【解决方案1】:

dplyrpurrr 选项可以是:

d %>%
 group_by(id) %>%
 mutate(nvar = map_dbl(.x = seq_along(iz), ~ min(abs(.x - which(iz == 1)))),
        nvar = if_else(cumsum(iz) == 0, -nvar, nvar))

   id     time    iz  nvar
   <fct> <dbl> <dbl> <dbl>
 1 a         1     0    -1
 2 a         2     1     0
 3 a         3     1     0
 4 a         4     0     1
 5 a         5     0     2
 6 b         1     0    -4
 7 b         2     0    -3
 8 b         3     0    -2
 9 b         4     0    -1
10 b         5     1     0
11 c         1     0    -3
12 c         2     0    -2
13 c         3     0    -1
14 c         4     1     0
15 c         5     1     0

【讨论】:

    【解决方案2】:

    1) rleid 此代码将 data.table 中的rleid 应用于每个 id,然后如果产生 1 的运行,则生成负反向序列,否则生成正向序列,即我们假设除了第一次运行之前,应该使用正向序列。对于iz 中的 1,将其归零。一个 id 中可以有任意数量的运行,它还支持只有 0 或只有 1 的 id。它假定时间没有间隔。

    library(data.table)
    
    Seq <- function(x, s = seq_along(x)) if (x[1] == 1) -rev(s) else s
    nvar <- function(iz, r = rleid(iz)) ave((1-iz) * r, r, FUN = Seq)
    transform(d, nvar = (1-iz) * ave(iz, id, FUN = nvar))
    

    给予:

       id time iz nvar
    1   a    1  0   -1
    2   a    2  1    0
    3   a    3  1    0
    4   a    4  0    1
    5   a    5  0    2
    6   b    1  0   -4
    7   b    2  0   -3
    8   b    3  0   -2
    9   b    4  0   -1
    10  b    5  1    0
    11  c    1  0   -3
    12  c    2  0   -2
    13  c    3  0   -1
    14  c    4  1    0
    15  c    5  1    0
    

    2) base 此代码仅使用 base R。它假定每个 id 最多有一次运行。是否有零没有限制。它还支持时间间隔。它将nvar 应用于每个id 的行号。首先,它计算时间的范围rng,然后计算nvar 最后一行的有符号距离。输出与 (1) 中所示的相同。如果我们可以假设每个 id 都恰好有一个 1,则可以省略 if 语句。

    nvar <- function(ix) with(d[ix, ], {
      if (all(iz == 0)) return(iz)
      rng <- range(time[iz == 1])
      (time < rng[1]) * (time - rng[1]) + (time > rng[2]) * (time - rng[2])
    })
    transform(d, nvar = ave(1:nrow(d), id, FUN = nvar))
    

    2a) (2) 的这种变体将 timeiz 传递给 nvar,通过将它们编码为复向量的实部和虚部,以避免不得不处理行数字,但在其他方面与 (2) 相同。我们在 (2) 中省略了 if 语句,但如果任何 id 都没有,则可以将其添加回来。

    nvar <- function(x, time = Re(x), iz = Im(x), rng = range(time[iz == 1])) 
      (time < rng[1]) * (time - rng[1]) + (time > rng[2]) * (time - rng[2])
    transform(d, nvar = Re(ave(time + iz * 1i, id, FUN = nvar)))
    

    【讨论】:

    • 请注意,如果时间不是一个很好的顺序,但有“间隙”,这将无法正常工作(我认为)
    • 确实,只是指出以防 TS 过度简化了他的样本数据
    • 感谢两位的精彩回答。两者都完美地工作。碰巧的是,我的时间变量中没有“间隙”。但是感谢您提出这种可能性。
    • 添加了第二种使用时间的方法,因此间隙是可以的。它假设每个 id 中恰好有一个运行。由于您似乎没有间隙,并且每个 id 都有一个运行,因此 (1) 和 (2) 可能同样有效。 (2) 不使用任何包。
    【解决方案3】:

    这是一个比 G.Grothendieck 的解决方案稍微复杂一点的解决方案。但是将能够处理非连续时间。

    library( data.table )
    #make d a data.table
    setDT(d)
    
    #you can remove the trailing [], they are just for passing the output to the console...
    #nvar = 0 where iz = 1
    d[ iz == 1, nvar := 0 ][]
    #calculate nvar for iz == 0 BEFORE iz == 1, using a forward rolling join
    #create subsets for redability
    d1 <- d[ iz == 1, ]
    d0 <- d[ iz == 0, ]
    d[ iz == 0, nvar := time - d1[ d0, x.time, on = .(id, time), roll = -Inf ] ][]
    #calculate nvar for iz == 0 AFTER iz == 1, usning a backward rolling join
    #create subsets for redability
    d1 <- d[ iz == 1, ]
    d0 <- d[ iz == 0 & is.na( nvar ), ]
    d[ iz == 0 & is.na(nvar) , nvar := time - d1[ d0, x.time, on = .(id, time), roll = Inf ] ][]
    
    #     id time iz nvar
    #  1:  a    1  0   -1
    #  2:  a    2  1    0
    #  3:  a    3  1    0
    #  4:  a    4  0    1
    #  5:  a    5  0    2
    #  6:  b    1  0   -4
    #  7:  b    2  0   -3
    #  8:  b    3  0   -2
    #  9:  b    4  0   -1
    # 10:  b    5  1    0
    # 11:  c    1  0   -3
    # 12:  c    2  0   -2
    # 13:  c    3  0   -1
    # 14:  c    4  1    0
    # 15:  c    5  1    0
    

    【讨论】:

    • 感谢您的回答温佩尔!由于另一个答案更重要,我接受它作为解决我问题的答案。但是,我要感谢您考虑可能会产生上述答案的问题。
    猜你喜欢
    • 2022-11-13
    • 2016-07-09
    • 2021-03-10
    • 2020-06-30
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    相关资源
    最近更新 更多