данные:
structure(list(id = c(1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5),
ax = c("a", "a", "b", "b", "b", "b", "b", "b", "c", "c",
"d", "d", "e"), time = c(1, 3, 0, 2, 4, 5, 6, 8, 7, 9, 10,
11, 12)), .Names = c("id", "ax", "time"), class = c("data.table",
"data.frame"), row.names = c(NA, -13L))
выглядит как:
id ax time
1: 1 a 1
2: 1 a 3
3: 2 b 0
4: 2 b 2
5: 2 b 4
6: 2 b 5
7: 2 b 6
8: 2 b 8
9: 3 c 7
10: 3 c 9
11: 4 d 10
12: 4 d 11
13: 5 e 12
Я хочу, чтобы max
предыдущей группы располагался рядом с фактической группой:
желаемый результат:
id ax time newCol
1: 1 a 1 NA
2: 1 a 3 NA
3: 2 b 0 3
4: 2 b 2 3
5: 2 b 4 3
6: 2 b 5 3
7: 2 b 6 3
8: 2 b 8 3
9: 3 c 7 8
10: 3 c 9 8
11: 4 d 10 9
12: 4 d 11 9
13: 5 e 12 11
Возможно ли также иметь значение группы «предыдущая-предыдущая»?
Заинтересован в решениях baseR
, data.table
и tidyverse
Может быть сгруппирован ЛИБО по id
или ax
. Пример здесь немного повторяется.
Вот подход dplyr
. Ключевым моментом здесь является группировка и разгруппировка при необходимости:
df %>%
group_by(ax) %>%
mutate(new = time[n()]) %>%
ungroup() %>%
mutate(new = lag(new)) %>%
group_by(ax) %>%
mutate(new = new[1])
# A tibble: 13 x 4
# Groups: ax [5]
id ax time new
<dbl> <chr> <dbl> <dbl>
1 1. a 1. NA
2 1. a 3. NA
3 2. b 0. 3.
4 2. b 2. 3.
5 2. b 4. 3.
6 2. b 5. 3.
7 2. b 6. 3.
8 2. b 8. 3.
9 3. c 7. 8.
10 3. c 9. 8.
11 4. d 10. 9.
12 4. d 11. 9.
13 5. e 12. 11.
Предполагая, что id
совпадает с group
:
dfr <- dfr %>% group_by(id) %>% mutate(groupmax = max(time))
dfr$old_group_max <- dfr$groupmax[match(dfr$id - 1, dfr$id)]
Предпоследняя группа оставлена в качестве упражнения :-)
Решение data.table
:
dtt.max <- dtt[, .(max = max(time)), by = ax]
dtt.max[, max.prev := shift(max)]
dtt[dtt.max, newCol := i.max.prev, on = 'ax']
# > dtt
# id ax time newCol
# 1: 1 a 1 NA
# 2: 1 a 3 NA
# 3: 2 b 0 3
# 4: 2 b 2 3
# 5: 2 b 4 3
# 6: 2 b 5 3
# 7: 2 b 6 3
# 8: 2 b 8 3
# 9: 3 c 7 8
# 10: 3 c 9 8
# 11: 4 d 10 9
# 12: 4 d 11 9
# 13: 5 e 12 11
Решение data.table
с использованием id + 1
library(data.table)
merge(d, setDT(d)[, max(time), id + 1], all.x = TRUE)
@AndreElrico Если id
числовой, то простое решение - простое добавление целого числа.
конечно в таком случае. Но, конечно, возможно, что идентификатор отсутствует и т.д ... в любом случае хороший материал !!!
почему-то я получаю следующую ошибку: Error in gmax(time) : grpn [13] != length(x) [11] in gmax
@AndreElrico Я использую data.table 1.10.4.3
Чтобы добавить его по ссылке вместо создания новой таблицы: DT[DT[, max(time), by=id+1], on=.(id), v := i.V1]
или DT[DT[, max(time), by=id][, id := shift(id, type = "lead")], on=.(id), v := i.V1]
1) Не использует пакеты. Он вычисляет максимум для каждой группы, дающей Ag
, а затем отстает, давая LagMax
. Наконец, он оставил соединения с использованием merge
, которые вернулись в исходный фрейм данных DF
:
Ag <- aggregate(time ~ id, DF, max)
LagMax <- transform(Ag, lagmax = c(NA, head(time, -1)), time = NULL)
merge(DF, LagMax, by = "id", all.x = TRUE)
давая:
id ax time lagmax
1 1 a 1 NA
2 1 a 3 NA
3 2 b 0 3
4 2 b 2 3
5 2 b 4 3
6 2 b 5 3
7 2 b 6 3
8 2 b 8 3
9 3 c 7 8
10 3 c 9 8
11 4 d 10 9
12 4 d 11 9
13 5 e 12 11
2) Сортировка времени внутри id, чтобы мы знали, что максимальное значение - это последнее значение в каждой группе id.
o <- order(factor(DF$id, levels = unique(DF$id)), DF$time)
Time <- DF$time[o]
lagmax <- function(r) if (r[1] == 1) NA else Time[r[1] - 1]
transform(DF, lagmax = ave(seq_along(id), id, FUN = lagmax))
В вопросе значения time
уже отсортированы в id
, и если это известно, то приведенное выше можно сократить до:
lagmax <- function(r) if (r[1] == 1) NA else DF$time[r[1] - 1]
transform(DF, lagmax = ave(seq_along(id), id, FUN = lagmax))
3) Этот однострочный перевод таблицы данных (2):
library(data.table)
DT <- copy(DF) # don't overwrite DF
setDT(DT)[, g:=rleid(id)][, lagmax := DT$time[.I[1]-1], keyby = c("g", "id")]
В образце данных в вопросе time
сортируется внутри id
, и если бы это было известно, мы могли бы использовать следующий более короткий код вместо последней строки выше
setDT(DT)[, lagmax := DT$time[.I[1]-1], by = id]
придумали что-то подобное, затем сдвиньте / прокрутите переменную id.