Вопрос или проблема
Каково решение для вычисления скользящего среднего для числовой переменной, которая наблюдается для двух групп в три периода?
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 для большей гибкости и контроля. Оба способа предоставляют один и тот же результат, поэтому вы можете выбирать, исходя из своих предпочтений и требований проекта.