Определите Accum
, который добавляет x
к acc
, сбрасывая к x
, если acc
равно 45 или более. Используйте Reduce
, чтобы применить это к Z
, давая r
(который является столбцом кумулятивной суммы). Значения, большие или равные 45, являются концами группы, поэтому присвойте им уникальный идентификатор группы в g
, используя cumsum
, начиная с конца и возвращаясь назад к началу, давая g
, который имеет уникальные значения для каждого группа. Наконец, измените идентификаторы групп в g
так, чтобы они начинались с 1. Мы выполняем это с вводом в примечании в конце, который дублирует последнюю строку несколько раз, чтобы можно было отобразить 3 группы. Пакеты не используются.
Accum <- function(acc, x) if (acc < 45) acc + x else x
applyAccum <- function(x) Reduce(Accum, x, accumulate = TRUE)
cumsumr <- function(x) rev(cumsum(rev(x))) # reverse cumsum
GroupNo <- function(x) {
y <- cumsumr(x >= 45)
max(y) - y + 1
}
transform(transform(DF, Cumsum = ave(Z, ID, FUN = applyAccum)),
Group = ave(Cumsum, ID, FUN = GroupNo))
дает:
ID X Y Z Cumsum Group
1 1 A A 1 1 1
2 2 A B 5 6 1
3 3 A C 2 8 1
4 4 A D 42 50 1
5 5 A E 10 10 2
6 6 A F 2 12 2
7 7 A G 0 12 2
8 8 A H 3 15 2
9 9 A I 0 15 2
10 10 A J 8 23 2
11 11 A K 19 42 2
12 12 A L 3 45 2
13 12 A L 3 3 3
14 12 A L 3 6 3
Примечание
Ввод в воспроизводимом виде:
Lines <- "ID X Y Z
1 A A 1
2 A B 5
3 A C 2
4 A D 42
5 A E 10
6 A F 2
7 A G 0
8 A H 3
9 A I 0
10 A J 8
11 A K 19
12 A L 3
12 A L 3
12 A L 3"
DF <- read.table(text = Lines, as.is = TRUE, header = TRUE)