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