如何在 R 中的不平衡面板数据中创建自上次事件以来的时间?

How to create time since last event in unbalance panel data in R?

我有不平衡的面板数据,其中有一个二进制变量指示事件是否发生。我想控制时间依赖性,所以我想创建一个变量来指示自上次事件以来已经过去的年数。数据按 dyad-year 组织。

这是一个可重现的示例,其中包含我要实现的目标的向量。谢谢!

   id year onset time_since_event
1   1 1989     0                1
2   1 1990     0                2
3   1 1991     1                0
4   1 1992     0                1
5   1 1993     0                2
6   2 1989     0                1
7   2 1990     1                0
8   2 1991     0                1
9   2 1992     1                0
10  3 1991     0                1
11  3 1992     0                2

˚

id <- c(1,1,1,1,1,2,2,2,2,3,3)
year <- c(1989,1990,1991,1992,1993,1989,1990,1991,1992,1991,1992)
onset <- c(0,0,1,0,0,0,1,0,1,0,0)
time_since_event<-c(1,2,0,1,2,1,0,1,0,1,2) #what I want to create
df <- data.frame(cbind(id, year, onset,time_since_event))

我们可以使用data.table。将 'data.frame' 转换为 'data.table'(setDT(df),基于 'onset' 列创建一个 运行 长度的 id 分组变量('ind')使用 rleid。按 'ind' 和 'id' 列分组,我们将 'time_since_event' 列指定为 'onset' 不等于 1 的行序列。在下一步中,将 'NA' 元素替换为 0.

library(data.table)#v1.9.6+
setDT(df)[, ind:=rleid(onset)][onset!=1, time_since_event:=1:.N , 
     by = .(ind, id)][is.na(time_since_event), time_since_event:= 0]

df
#     id year onset ind time_since_event
# 1:  1 1989     0   1                1
# 2:  1 1990     0   1                2
# 3:  1 1991     1   2                0
# 4:  1 1992     0   3                1
# 5:  1 1993     0   3                2
# 6:  2 1989     0   3                1
# 7:  2 1990     1   4                0
# 8:  2 1991     0   5                1
# 9:  2 1992     1   6                0
#10:  3 1991     0   7                1
#11:  3 1992     0   7                2

或者可以做得紧凑。按 rleid(onset) 和 'id' 列分组,我们对 'onset' 求反(因此 0 变为 TRUE,1 变为 FALSE),乘以行序列 (1:.N) 并赋值 (:=) 它作为 'time_since_event' 列。

setDT(df)[,time_since_event := 1:.N *!onset, by = .(rleid(onset), id)]
df
#    id year onset time_since_event
# 1:  1 1989     0                1
# 2:  1 1990     0                2
# 3:  1 1991     1                0
# 4:  1 1992     0                1
# 5:  1 1993     0                2
# 6:  2 1989     0                1
# 7:  2 1990     1                0
# 8:  2 1991     0                1
# 9:  2 1992     1                0
#10:  3 1991     0                1
#11:  3 1992     0                2

或者我们可以使用dplyr。我们按 'id' 分组并创建另一个变量(通过取 'onset' 中相邻元素的差异(diff),创建逻辑索引(!=0)和 cumsum索引)。在 mutate 中,我们将行序列 (row_number()) 与取反的 'onset' 相乘(就像之前一样),并使用 select 删除 'ind' 列。

library(dplyr)
df %>% 
    group_by(id, ind= cumsum(c(TRUE, diff(onset)!=0))) %>% 
    mutate(time_since_event= (!onset) *row_number()) %>%
    ungroup() %>%
    select(-ind) 
#     id  year onset time_since_event
#   (dbl) (dbl) (dbl)            (int)
#1      1  1989     0                1
#2      1  1990     0                2
#3      1  1991     1                0
#4      1  1992     0                1
#5      1  1993     0                2
#6      2  1989     0                1
#7      2  1990     1                0
#8      2  1991     0                1
#9      2  1992     1                0
#10     3  1991     0                1
#11     3  1992     0                2

数据

df <- data.frame(id, year, onset)