ГЛАВА 3 Агрегирование наблюдений
Обычной задачей при работе с временными рядами является расчет агрегированных показателей за определенный календарный период (например, средние или суммарные значения за день, неделю, месяц, квартал и т.п.). В пакете tsibble
(разд. 1.4) для таких вычислений используется связка из двух функций: index_by()
и summarise()
. Первая из этих функций входит в состав пакета tsibble
и аналогична group_by()
из пакета dplyr
. Как следует из ее названия, index_by()
группирует данные по заданному пользователем периоду времени. Для указания необходимого периода применяются такие функции из пакета tsibble
, как yearweek()
(неделя), yearmonth()
(месяц) и yearquarter()
(квартал). Кроме того, можно также использовать базовую as.Date()
и многие функции из пакета lubridate
(Grolemund and Wickham 2011). Вторая функция из указанной выше связки — summarise()
— входит в состав пакета dplyr
и служит для вычисления необходимых агрегированных величин.
Воспользуемся данными cryptos
(подразд. 1.5.1) и в качестве примера рассчитаем среднемесячную стоимость каждой криптовалюты, а также общее число наблюдений, учтенных в каждом месяце исследованного периода:
require(dplyr)
monthly <- cryptos %>%
group_by_key() %>%
index_by(year_month = ~ yearmonth(.)) %>%
summarise(
avg_y = mean(y),
n = n()
)
monthly
## # A tsibble: 528 x 4 [1M]
## # Key: coin [22]
## coin year_month avg_y n
## <chr> <mth> <dbl> <int>
## 1 augur 2018 Jan 84.1 31
## 2 augur 2018 Feb 51.1 28
## 3 augur 2018 Mar 35.9 31
## 4 augur 2018 Apr 32.5 30
## 5 augur 2018 May 45.8 31
## 6 augur 2018 Jun 34.5 30
## 7 augur 2018 Jul 31.9 31
## 8 augur 2018 Aug 21.7 31
## 9 augur 2018 Sep 14.7 30
## 10 augur 2018 Oct 13.1 31
## # ... with 518 more rows
Заметьте, что перед вычислением агрегированных показателей мы сначала сгруппировали данные по каждой криптовалюте с помощью функции group_by_key()
. Поскольку в этом наборе данных есть только одна группирующая переменная (coin
) и она была задана при создании таблицы cryptos
, то при вызове group_by_key()
не было необходимости указывать эту группирующую переменную в явном виде.
Результат вычисления среднемесячной стоимости анализируемых криптовалют показан на рис. 3.1:
require(ggrepel)
monthly %>%
mutate(label = ifelse(year_month == max(year_month), coin, NA)) %>%
ggplot(., aes(year_month, avg_y, group = coin)) +
geom_line() + scale_y_log10() +
geom_text_repel(aes(label = label),
size = 3, nudge_x = 50,
segment.size = 0.4,
segment.color = "gray60",
point.padding = 0.2,
force = 4, na.rm = TRUE) +
xlim(c(yearmonth("2018-01"), yearmonth("2020-06"))) +
theme_minimal()
Еще одной распространенной задачей при работе с временными рядами является расчет агрегированных показателей в пределах скользящего блока (“окна”) данных. В пакете tsibble
для таких вычислений есть несколько функций со следующими приставками в названии:
slide_
— выполняют вычисления в пределах перекрывающихся окон размером.size
(размер “нахлеста” контролируется с помощью аргумента.step
);tile_
— вычисления ведутся в пределах следующих друг за другом, но неперекрывающихся окон размером.size
;stretch_
— исходная ширина окна.init
постепенно увеличивается на.step
временных отметок.
В зависимости от типа возвращаемых значений названия перечисленных выше функций заканчиваются на lgl
(логические), int
(целые числа), dbl
(действительные числа) или chr
(строковые значения). Например, при работе с действительными числами агрегирование по скользящему окну с перекрывающимися наблюдениями выполняется с помощью функции slide_dbl()
.
В качестве примера вычислим скользящую среднюю стоимость каждой из 22 криптовалют в пределах окна шириной 14 дней, которое каждый раз передвигается на одну временную отметку вперед:
cryptos_ma <- cryptos %>%
group_by_key() %>%
mutate(moving_avg_y = slide_dbl(y, ~mean(.), .size = 14, .step = 1))
На рис. 3.2 показаны результаты вычисления скользящей средней для двух случайно выбранных криптовалют:
set.seed(1984)
cryptos_ma %>% ungroup() %>%
filter(coin %in% sample(unique(coin), 2)) %>%
ggplot(aes(ds, y)) +
geom_point(alpha = 0.1) +
geom_line(aes(ds, moving_avg_y), col = "blue") +
facet_wrap(~coin, ncol = 1) +
scale_y_log10() + theme_minimal()