Группировать по совокупным суммам с условиями

#r #dplyr #cumsum

#r #dplyr #сумма

Вопрос:

В этом фрейме данных:

 df <- data.frame(
  ID = c("C", "B", "B", "B", NA, "C", "A", NA, "B", "B", "B")
)
 

Я хотел бы сгруппировать строки, используя cumsum два условия: (i) cumsum не должно продолжаться, если is.na(ID) и (ii) оно не должно продолжаться, если следующее ID значение совпадает с предыдущим. Я действительно выполняю условие (i) с этим:

 df %>%
  group_by(grp = cumsum(!is.na(ID)))
# A tibble: 11 x 2
# Groups:   grp [9]
   ID      grp
   <chr> <int>
 1 C         1
 2 B         2
 3 B         3
 4 B         4
 5 NA        4
 6 C         5
 7 A         6
 8 NA        6
 9 B         7
10 B         8
11 B         9
 

но я не знаю, как реализовать условие (ii) тоже, чтобы получить желаемый результат:

  1 C         1
 2 B         2
 3 B         2
 4 B         2
 5 NA        2
 6 C         3
 7 A         4
 8 NA        4
 9 B         5
10 B         5
11 B         5
 

Я пробовал это с этим, но у меня не работает:

 df %>%
  group_by(grp = cumsum(!is.na(ID) |!lag(ID,1) == ID))
 

Ответ №1:

Используйте na.locf0 из zoo для заполнения NAs, а затем примените rleid из data.table:

 library(data.table)
library(zoo)

rleid(na.locf0(df$ID))
##  [1] 1 2 2 2 2 3 4 4 5 5 5
 

Ответ №2:

Используя tidyr и dplyr , вы могли бы сделать:

 df %>%
 mutate(grp = fill(., ID) %>% pull(),
        grp = cumsum(grp != lag(grp, default = first(grp))))

     ID grp
1     C   0
2     B   1
3     B   1
4     B   1
5  <NA>   1
6     C   2
7     A   3
8  <NA>   3
9     B   4
10    B   4
11    B   4
 

Ответ №3:

Используя rle

 library(zoo)
with(rle(na.locf0(df$ID)), rep(seq_along(values), lengths))
#[1] 1 2 2 2 2 3 4 4 5 5 5