Найдите строку со значением, отличным от предыдущей строки в R dplyr

У меня есть фрейм данных, x — номер строки по группе, переменная значения, а изменение отличается от предыдущей строки.

Я хотел бы создать групповую переменную. Если переменная изменения отличается от предыдущей переменной, мы устанавливаем номер строки, но если он одинаковый, мы устанавливаем тот же номер строки из первого значения.

df <- data.frame(x = c(1:11),
           value = c(0, 3, 1, 1, 3, 1, 2, 0, 0, 0, 0),
           change = c(0, -3, 2, 2, -3, 2, -1, 0, 0, 0, 0))

> df
    x value change
1   1     0      0
2   2     3     -3
3   3     1      2
4   4     1      2
5   5     3     -3
6   6     1      2
7   7     2     -1
8   8     0      0
9   9     0      0
10 10     0      0
11 11     0      0

Вот желание df

> df <- data.frame(x = c(1:11),
+            value = c(0, 3, 1, 1, 3, 1, 2, 0, 0, 0, 0),
+            change = c(0, -3, 2, 2, -3, 2, -1, 0, 0, 0, 0),
+            group = c(1, 2, 3, 3, 5, 6, 7, 8, 8, 8, 8))
> df
    x value change group
1   1     0      0     1
2   2     3     -3     2
3   3     1      2     3
4   4     1      2     3
5   5     3     -3     5
6   6     1      2     6
7   7     2     -1     7
8   8     0      0     8
9   9     0      0     8
10 10     0      0     8
11 11     0      0     8


76
2

Ответы:

Решено

1) Используйте consecutive_id, чтобы присвоить возрастающие значения последовательным группам, и используйте их, чтобы заполнить каждую группу номером строки первого элемента этой группы.

library(dplyr)

make_group <- function (x) {
  g <- consecutive_id(x)
  match(g, g)
}

df %>%
  mutate(group = make_group(change))

предоставление

    x value change group
1   1     0      0     1
2   2     3     -3     2
3   3     1      2     3
4   4     1      2     3
5   5     3     -3     5
6   6     1      2     6
7   7     2     -1     7
8   8     0      0     8
9   9     0      0     8
10 10     0      0     8
11 11     0      0     8

2) В этом подходе мы группируем номер_строки по последовательному_идентификатору и берем первый. Вывод такой же, как (1).

df %>%
  mutate(group = ave(row_number(), consecutive_id(change), FUN = first))

2a) В этом варианте (2) используется match в .by=. Обратите внимание, что mutate — это номер строки в x. Это снова дает тот же ответ:

df %>%
  mutate(consec = consecutive_id(change)) %>%
  mutate(group = first(x), .by = consec) %>%
  select(-consec)

В базе R можно адаптировать известный consecutive_id-подход на основе rle() в сочетании с простым ave-вызовом:

consecutive_id = \(x) with(rle(x), rep(seq_along(values), lengths))
df$group = ave(seq(nrow(df)), consecutive_id(df$change), FUN = \(x) x[1L])

предоставление

> df
    x value change group
1   1     0      0     1
2   2     3     -3     2
3   3     1      2     3
4   4     1      2     3
5   5     3     -3     5
6   6     1      2     6
7   7     2     -1     7
8   8     0      0     8
9   9     0      0     8
10 10     0      0     8
11 11     0      0     8