Создать новую переменную счетчика в зависимости от предыдущих значений в группе

У меня есть фреймворк с группой и идентификатором времени. Теперь я хочу создать новую переменную счетчика, названную X2, в зависимости от предыдущих значений X1 в каждой группе.

Предположим, у меня есть следующий фрейм данных, переменные group, time, X1, и я хочу создать X2. Значение X2 должно быть переменной счетчика, указывающей количество периодов (т. Е. Строк), поскольку 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))

Я мог бы легко создать NA, используя команду if с cumsum()==0. Однако я понятия не имею, как подойти к другой части, т.е. создать счет.

Любая помощь будет принята с благодарностью - если это вообще возможно, используя dplyr.

Большое спасибо.


person Tim Welsh    schedule 09.04.2020    source источник


Ответы (2)


Это не очень элегантно, но, как мне кажется, включает в себя предусмотренные правила.

Столбец добавляется для номеров строк, где X1 равно 1, а fill используется, чтобы вы могли использовать самый последний номер строки, доступный для этого условия.

Чтобы вычислить X2_new, если X1 равно 0, это разница между номером текущей строки в группе минус номер последней строки, где X1 было 1. Если X1 равно 1 (а не первый X1 из 1 в группе), тогда выполните аналогичный расчет, но по предыдущей 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
person Ben    schedule 09.04.2020

Использование функций конвейера (%>%), mutate, group_by и lag из пакета dplyr

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))))
person bbakes    schedule 09.04.2020