R 创建事件发生时间和事件发生时间变量

R 创建事件发生时间和事件发生时间变量,r,tidyverse,panel-data,R,Tidyverse,Panel Data,我正在处理的面板数据如下所示: d <- data.frame(id = c("a", "a", "a", "a", "a", "b", "b", "b", "b", "b", "c", "c", "c", "c"

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

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
  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
我已经尝试过使用给出的答案,但无法在我的案例中使用

我真的很想知道如何解决这个问题。提前感谢您的所有想法和建议。

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))
2)base此代码仅使用base R。它假设每个id最多运行一次。对是否有零没有任何限制。它还支持时间间隔。它将
nvar
应用于每个id的行号。首先,它计算这些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))

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

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
库(data.table)
#制作一个数据表
setDT(d)
#您可以删除尾部[],它们只是用于将输出传递到控制台。。。
#nvar=0,其中iz=1
d[iz==1,nvar:=0][]
#使用前向滚动联接,在iz==1之前计算iz==0的nvar
#为可编辑性创建子集

d1一个
dplyr
purrr
选项可以是:

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
d%>%
分组依据(id)%>%
变异(nvar=map_dbl(.x=seq_沿着(iz),~min(abs(.x-which(iz==1))),
nvar=if_else(总和(iz)==0,-nvar,nvar))
id时间iz nvar
1A 10-1
2 a 2 1 0
3 a 3 1 0
4 a 4 0 1
5 a 5 0 2
6 b 10-4
7 b 2 0-3
8B30-2
9 b 4 0-1
10 b 5 1 0
11 c 10-3
12 c 2 0-2
13 c 30-1
14C410
15 c 5 1 0

每个
id
是否只有一个事件/治疗?如果没有,并且可能有多个事件,您希望如何处理事件之间的
nvar
?很抱歉没有澄清。理想情况下,此类观察将被视为“事后”观察。我尝试了下面的机器人示例,Grothedicks的答案就是这样,而Wimpels的答案将它们计算为“pre”。请注意,如果时间不是一个很好的序列,但确实有“间隙”,那么这将无法正确工作(我认为),只要指出它,以防TS过于简化了他的样本数据谢谢你们两位伟大的答案。两者都能完美地工作。碰巧的是,我的时间变量中没有“间隙”。但是谢谢你提出这个可能性。我们增加了第二种方法,它使用时间,所以间隔是可以的。它假设每个id中正好有一个运行的id。因为似乎没有间隙,而且每个id都有一个运行的id,所以(1)和(2)的工作可能是相同的。(2) 不使用任何软件包。谢谢您的回答!由于另一个答案更切题,我接受了这个答案,因为它解决了我的问题。然而,我要感谢你们思考了可能产生上述答案的问题。
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
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