Динамический роллприменить в R

Я думаю получить максимум (N-1) строк по группе в R (но не включая текущую строку). Не уверен, с чего мне начать, поскольку каждая группа имеет динамическое количество строк. Например:

Пример того, что я хочу

Спасибо =)


person skw1990    schedule 01.04.2018    source источник
comment
Было бы хорошо, если бы вы могли преобразовать картинку в текст. Таким образом, когда ссылка imgur исчезнет, ​​ваш вопрос все равно будет полезен другим.   -  person    schedule 01.04.2018
comment
Я не думаю, что ссылка, скорее всего, исчезнет, ​​поскольку SO сама предоставляет такие ссылки, но отвечающим на вопрос придется вручную повторно вводить ввод, если он не указан в текстовой форме.   -  person G. Grothendieck    schedule 01.04.2018


Ответы (3)


Используя DF, определенное воспроизводимо в примечании в конце, мы можем использовать rollapply для применения max, взяв максимальное из всех предыдущих значений, где указание ширины от list(-seq(.N)) до rollapply означает использование смещений -1, -2, ..., -.N . partial=TRUE говорит использовать любое количество доступных значений среди указанных смещений, даже если некоторые из смещений недоступны. Наконец, запустите его для каждой группы, используя by=.

Это решение использует rollapply и data.table по запросу и включает прямое указание того, какие смещения использовать, а не сдвиг или отставание.

Мы могли бы изменить max на min, sum, mean, median или что-то еще, что подходит, если бы мы этого хотели. Если бы мы хотели изменить это, чтобы просто найти максимальное из предыдущих значений k, мы могли бы заменить -seq(.N) на -seq(k).

library(data.table)
library(zoo)

DT <- as.data.table(DF)
DT[, max := rollapply(Count, list(-seq(.N)), max, partial = TRUE, fill = NA), by = Group]

давая:

> DT
   Group Count max
1:     A    23  NA
2:     A    12  23
3:     A   145  23
4:     B   123  NA
5:     B    34 123
6:     B   456 123
7:     B   555 456

Примечание

Вход DF в воспроизводимой форме:

DF <- data.frame(Group = c("A", "A", "A", "B", "B", "B", "B"),
                 Count = c(23, 12, 145, 123, 34, 456, 555))

Обновлять

Исправил оригинал и обновил его более коротким решением, которое использует data.table в соответствии с тегом data.table в вопросе.

person G. Grothendieck    schedule 01.04.2018
comment
Хорошее решение. Спасибо! - person skw1990; 01.04.2018

Возможное решение с пакетом data.table и функциями cummax и shift:

library(data.table)
setDT(df)[, lagged_max := shift(cummax(Count)), by = Group][]

который дает:

> df
   Group Count lagged_max
1:     A    23         NA
2:     A    12         23
3:     A   145         23
4:     B   123         NA
5:     B    34        123
6:     B   456        123
7:     B   555        456

Что это делает:

  • setDT(df) преобразует фрейм данных df в data.table.
  • cummax(Count) получает кумулятивный максимум Count.
  • С shift результат смещается на одну позицию вверх, потому что значения по умолчанию для параметров n, type и fill равны 1L, lag и NA соответственно. Записано полностью: shift(cummax(Count), n = 1L, type = 'lag', fill = NA).

Та же логика в базе R:

transform(df, lagged_max = ave(Count, Group, FUN = function(x) c(NA, head(cummax(x), -1))))

Или с dplyr:

library(dplyr)
df %>% 
  group_by(Group) %>% 
  mutate(lagged_max = lag(cummax(Count)))

Используемые данные:

df <- data.frame(Group = c("A", "A", "A", "B", "B", "B", "B"),
                 Count = c(23, 12, 145, 123, 34, 456, 555))
person Jaap    schedule 01.04.2018

Вот решение с использованием dplyr::lag:

# Sample data
df <- data.frame(
    Group = c("A", "A", "A", "B", "B", "B", "B"),
    Count = c(23, 12, 145, 123, 34, 456, 555))

library(tidyverse);
df %>%
    group_by(Group) %>%
    mutate(
        n1 = lag(Count, 1),
        n2 = lag(Count, 2),
        max = ifelse(!is.na(n2) & !is.na(n1) & n2 > n1, n2, n1)) %>%
    select(-n1, -n2)
## A tibble: 7 x 3
## Groups:   Group [2]
#  Group Count   max
#  <fct> <dbl> <dbl>
#1 A       23.   NA
#2 A       12.   23.
#3 A      145.   23.
#4 B      123.   NA
#5 B       34.  123.
#6 B      456.  123.
#7 B      555.  456.
person Maurits Evers    schedule 01.04.2018
comment
Ваши результаты не соответствуют результатам в вопросе. - person Joshua Ulrich; 01.04.2018
comment
@JoshuaUlrich Спасибо, исправлено. - person Maurits Evers; 01.04.2018