Сглаженное скользящее среднее

Вопрос или проблема

Каково решение для вычисления скользящего среднего для числовой переменной, которая наблюдается для двух групп в три периода?

df <- data.frame(
  Day = c(1, 2, 3, 1, 2, 3),
  Id = c("A", "A", "A", "B", "B", "B"),
  Num = c(1, 2, 3, 1, 3, 9)
)

Решение с помощью dplyr достаточно простое, но есть ли очевидный способ сделать это с помощью base?

library(dplyr)

df %>%
  group_by(Id) %>%
  mutate(RollingAvg = (Num + lag(Num))/2)

Если вы не хотите писать обертку (b_lag), которая делает то, что делает dplyr::lag(), вы можете использовать embed(). Попробуйте ave():

b_lag = \(x, k, fill = NA) c(rep(fill, k), head(x, -k))
within(df, { RollingAvg = ave(Num, Id, FUN = \(x) (x + b_lag(x, 1)) / 2) })

Результат:

  Day Id Num RollingAvg
1   1  A   1         NA
2   2  A   2        1.5
3   3  A   3        2.5
4   1  B   1         NA
5   2  B   3        2.0
6   3  B   9        6.0

Примечание. within() используется для вывода в том виде, как есть. Вы также могли бы сделать так:

df$RollingAvg = with(df, ave(Num, Id, FUN = \(x) (x + b_lag(x, 1)) / 2))

Ответ или решение

Вопрос: Какое решение для расчета скользящего среднего для числовой переменной, наблюдаемой для двух групп в течение трех периодов?

Для расчета скользящего среднего в R для группированных данных можно использовать как библиотеку dplyr, так и базовые функции. Ниже представлено решение этой задачи с использованием обоих подходов.

Исходные данные

Для начала создадим наш дата-фрейм:

df <- data.frame(
  Day = c(1, 2, 3, 1, 2, 3),
  Id = c("A", "A", "A", "B", "B", "B"),
  Num = c(1, 2, 3, 1, 3, 9)
)

Использование dplyr

С помощью библиотеки dplyr можно легко рассчитать скользящее среднее, группируя данные по идентификатору (Id) и используя функцию lag():

library(dplyr)

df <- df %>%
  group_by(Id) %>%
  mutate(RollingAvg = (Num + lag(Num)) / 2)

Это дает следующий результат:

# A tibble: 6 × 4
# Groups:   Id [2]
    Day Id     Num RollingAvg
  <dbl> <chr> <dbl>      <dbl>
1     1 A         1         NA
2     2 A         2        1.5
3     3 A         3        2.5
4     1 B         1         NA
5     2 B         3        2  
6     3 B         9        6  

Использование базового R

Если вы предпочитаете использовать базовые функции R, вы можете применить функцию ave() для получения нужного результата. Так как функция lag() не является частью базового R, можно создать аналогичную функцию:

b_lag <- function(x, k, fill = NA) {
  c(rep(fill, k), head(x, -k))
}

df <- within(df, {
  RollingAvg = ave(Num, Id, FUN = function(x) (x + b_lag(x, 1)) / 2)
})

Или можно использовать функцию with():

df$RollingAvg <- with(df, ave(Num, Id, FUN = function(x) (x + b_lag(x, 1)) / 2))

В результате вы получите тот же дата-фрейм:

  Day Id Num RollingAvg
1   1  A   1         NA
2   2  A   2        1.5
3   3  A   3        2.5
4   1  B   1         NA
5   2  B   3        2.0
6   3  B   9        6.0

Заключение

Вы можете выбрать метод, который вам больше нравится: использование dplyr для удобства и быстроты или базовые функции R для большей гибкости и контроля. Оба способа предоставляют один и тот же результат, поэтому вы можете выбирать, исходя из своих предпочтений и требований проекта.

Оцените материал
Добавить комментарий

Капча загружается...