根据组内的先前值创建新的计数变量

Create new count variable conditional on previous values within group

我有一个包含组和时间 ID 的数据框。现在我想创建一个新的计数变量,称为 X2,以每个组中 X1 的先前值为条件。

假设我有以下数据框、变量 grouptimeX1,并且想要创建 X2X2 的值应该是一个计数变量,指示自 X1 最后一次在给定组中等于 1 以来的周期数(即行数)。如果 X1 的所有先前值均为 0,则 X2 应该缺失。

          group     time       X1        X2 
1          1         1         0         NA  
2          1         2         0         NA  
3          1         3         1         NA  
4          1         4         0         0  
5          1         5         1         1
6          2         1         0         NA  
7          2         2         1         NA  
8          2         3         1         0  
9          2         4         1         0  
10         2         5         0         0  
11         3         1         0         NA  
12         3         2         0         NA  
13         3         3         0         NA  
14         3         4         1         NA  
15         3         5         0         0  
16         4         1         1         NA  
17         4         2         0         0  
18         4         3         0         1  
19         4         4         0         2  
20         4         5         1         3    
data_test <- data.frame(
   group = rep(1:4, each = 5), 
   time = rep(1:5, n = 4), 
   X1 = c(0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1), 
   X2 = c(NA, NA, NA, 0, 1, NA, NA, 0, 0, 0, NA, NA, NA, NA, 0, NA, 0, 1, 2, 3))

我可以通过使用带 cumsum()==0 的 if 命令轻松创建 NA。但是,我不知道如何处理另一部分,即创建计数。

任何帮助将不胜感激 - 如果可能的话使用 dplyr

非常感谢。

使用 dplyr

中的管道 (%>%)、mutategroup_bylag 函数
library(dplyr)
data_test %>%
  group_by(group) %>%
  mutate(X2 = ifelse(lag(X1) == 1, 0, lag(X2) + 1))

这确实假设 time 中的差异始终为 1,如示例数据所示。如果 time 在您的数据中有所不同,并且 X2 应该反映 time 中的差异:

data_test %>%
  group_by(group) %>%
  mutate(X2 = ifelse(lag(X1) == 1, 0, lag(X2) + (time - lag(time))))

这不是很优雅,但它包含了我认为提供的规则。

X1 为 1 的行号添加一列,并使用 fill,以便您可以使用适用于该条件的最新行号。

要计算X2_new,如果X1为0,则为组内当前行号减去X1为1的最后行号之间的差值。如果X1 是 1(而不是组中 1 的第一个 X1),然后做类似的计算,但在前面的 rn 参考上。

library(tidyverse)

data_test %>%
  group_by(group) %>%
  mutate(rn = ifelse(X1 == 1, row_number(), NA)) %>%
  fill(rn) %>%
  mutate(X2_new = ifelse(X1 == 0 & row_number() > rn, row_number() - rn - 1, NA),
         X2_new = ifelse(X1 == 1 & !is.na(lag(rn)), row_number() - lag(rn) - 1, X2_new)) %>%
  select(-rn)

输出

# A tibble: 20 x 5
# Groups:   group [4]
   group  time    X1    X2 X2_new
   <int> <int> <dbl> <dbl>  <dbl>
 1     1     1     0    NA     NA
 2     1     2     0    NA     NA
 3     1     3     1    NA     NA
 4     1     4     0     0      0
 5     1     5     1     1      1
 6     2     1     0    NA     NA
 7     2     2     1    NA     NA
 8     2     3     1     0      0
 9     2     4     1     0      0
10     2     5     0     0      0
11     3     1     0    NA     NA
12     3     2     0    NA     NA
13     3     3     0    NA     NA
14     3     4     1    NA     NA
15     3     5     0     0      0
16     4     1     1    NA     NA
17     4     2     0     0      0
18     4     3     0     1      1
19     4     4     0     2      2
20     4     5     1     3      3