Временные ряды | Вводный курс ML

Временные ряды

Все курсы > Вводный курс > Занятие 20

Понятие временного ряда

Временной ряд (time series) — это данные, последовательно собранные в регулярные промежутки времени.

К таким данным относятся, например, цены на акции, объемы продаж чего-либо, изменения температуры с течением времени и т.д. Посмотрим на изменение обычных данных и временных рядов.

отличие структурных/перекрестных данных от временного ряда

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

Работа с временными рядами предполагает два аспекта:

  1. Анализ временного ряда (time series analysis), т.е. понимание его структуры и закономерностей; и
  2. Моделирование и построение прогноза на будущее (time series forecasting)

Договоримся о терминах:

  • Во-первых, определим нотацию периодов. Временем t обозначим настоящее, t−1, t−2,… прошлое, t+1, t+2,… будущее.
  • Во-вторых, введем важное понятие временного лага (lag), т.е. запаздывания по сравнению с заданным периодом.
терминология временных рядов

Датасеты

Мы будем использовать два популярных набора данных, а именно (1) ежемесячные данные о количестве пассажиров, перевезенных одной американской авиакомпанией с 1949 по 1960 годы и (2) ежедневные данные о родившихся в Калифорнии в 1959 году девочках.

Подгружать внешние данные в ноутбук Google Colab мы уже умеем. Можем переходить непосредственно к работе с кодом.

Откроем ноутбук к этому занятию

Анализ временных рядов

Импорт данных и работа в библиотеке Pandas

Для начала давайте импортируем данные. Пока что мы будем использовать только первый набор данных с информацией об авиаперевозках.

временной ряд: данные о пассажирах авиакомпании

Сделаем дату индексом.

данные о пассажирах: дата стала индексом

Питон воспринимает дату как число. Это не очень удобно, если мы хотим делать срезы и в целом изменять данные во времени. Дату можно преобразовать в специальный объект datetime.

Все эти операции также можно проделать в одну строчку.

Теперь мы можем делать срезы за определенный период, например, с августа 1949 по март 1950 года.

срез временного ряда

Обратите внимание, что в отличие от других перечней в Питоне (например, списков), во временном ряде мы получаем данные и по начальной, и по конечной дате среза (в частности, март 1950 года вошел в наш интервал).

Изменение шага временного ряда, сдвиг и скользящее среднее

Отдельно хотелось бы поговорить про возможность обобщения и изменения данных. Помимо прочего, мы можем изменить шаг (resample) нашего временного ряда, и посмотреть средние показатели перевозок, например, за год.

изменение шага временного ряда (resample)

Кроме того, мы можем сдвинуть (shift) наши данные на n периодов вперед или назад.

сдвиг временного ряда (shift)

Что логично, после сдвига первые два значения определяются как пропущенные (NaN или Not a number).

Мы также можем рассчитать скользящее среднее (moving average, rolling average) за n предыдущих периодов. Вначале посмотрим, что это такое.

пример трехдневного скользящего среднего (moving average)

Теперь давайте рассчитаем его для наших данных. Период, за который рассчитывается скользящее среднее, также называется окном (window).

скользящее среднее в библиотеке pandas

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

Построение графиков

Для того чтобы построить график временного ряда мы можем воспользоваться инструментами, которые уже содержатся в библиотеке Pandas. Например, простым методом .plot().

график временного ряда в библиотеке pandas

График можно усложнить.

усложненный график временного ряда в библиотеке pandas

Визуализацию можно также построить с помощью библиотеки Matplotlib. Давайте выведем на одном графике перевозки пассажиров и скользящее среднее.

перевозки пассажиров по месяцам и скользящее среднее за 12 месяцев

Как вы видите, скользящее среднее сильно сглаживает показатели. Также обратите внимание, что так как в данном случае мы взяли окно равное двенадцати месяцам, то первое значение скользящего среднего мы получили только за декабрь 1949 года (самое начало желтой кривой на графике).

В целом не стоит недооценивать важность визуальной оценки ряда на графике. Многие особенности можно выявить именно так.

Разложение временного ряда на компоненты

Выявление компонентов временного ряда (time series decomposition) предполагает его разложение на тренд, сезонность и случайные колебания. Дадим несколько неформальных определений.

  • Тренд — долгосрочное изменение уровня ряда
  • Сезонность предполагает циклические изменения уровня ряда с постоянным периодом
  • Случайные колебания — непрогнозируемое случайное изменение ряда

В Питоне в модуле statsmodels есть функция seasonal_decompose(). Воспользуемся ей для визуализации компонентов ряда.

Перед этим импортируем второй датасет для последующего сравнения.

временной ряд: рождаемость в 1959 году

Теперь давайте разложим наш временной ряд по авиаперевозкам на компоненты.

разложение временного ряда по авиаперевозкам на компоненты

Сделаем то же самое с данными о рождаемости.

разложение временного ряда по рождаемости на компоненты

Как мы видим, графики совершенно разные. В следующем разделе мы изучим это различие более подробно.

Стационарность

Стационарность (stationarity) временного ряда как раз означает, что такие компоненты как тренд и сезонность отсутствуют. Говоря более точно, среднее значение и дисперсия не меняются со смещением во времени.

Понимание того, стационарные ли у нас данные или нестационарные важно для последующего моделирования.

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

Для более точной оценки стационарности можно применить тест Дики-Фуллера (Dickey-Fuller test). О том, что такое статистический вывод мы с вами уже говорили.

В данном случае гипотезы звучат следующим образом.

  • Нулевая гипотеза предполагает, что процесс нестационарный
  • Альтернативная гипотеза соответственно говорит об обратном

Применим этот тест к обоим датасетам. Используем пороговое значение, равное 0,05 (5%).

Как мы видим, вероятность (p-value) для данных о перевозках существенно выше 0,05. Мы не можем отвергнуть нулевую гипотезу. Процесс нестанионарный. Проведем тест для второго набора данных.

Результат существенно меньше 5%. Временной ряд стационарен.

Надо сказать, что наша визуальная оценка полностью совпала с математическими вычислениями.

Автокорреляция

Изучая статистику, мы с вами уже познакомились с корреляцией. Корреляция показывает силу взаимосвязи двух переменных и позволяет строить модель.

Автокорреляция также показывает степень взаимосвязи в диапазоне от –1 до 1, но только не двух переменных, а одной и той же переменной в разные моменты времени.

Допустим, у нас есть временной ряд и этот же ряд, взятый с лагом 1, 2 и 3.

временной ряд и его лаги

Мы можем посчитать автокорреляцию ряда с лагом 1.

Визуально это будет выглядеть следующим образом (вспомните график обычной корреляции).

пример автокорреляции с лагом 1

Аналогично мы можем посчитать корреляцию для лагов 2 и 3 и на самом деле любого другого лага. Такие измерения автокорреляции удобно вычислить и изобразить с помощью графика автокорреляционной функции (autocorrelation function, ACF).

автокорреляционная функция (ACF)

В частности, мы видим, что автокорреляция ряда с самим собой (первый столбец) равна 1, что логично. Второй столбец (то есть лаг 1) как раз примерно равен – 0,71.

Разные значения, полученные через np.corrcoef() и plot_acf(), объясняются небольшим различием в заложенных в этих функциях формулах.

Теперь построим график ACF для наших данных о перевозках.

автокорреляционная функция (ACF) временного ряда по авиаперевозкам

Автокорреляция позволяет выявлять тренд и сезонность, а также используется при подборе параметров моделей. В частности, мы видим, что лаг 12 сильнее коррелирует с исходным рядом, чем соседние лаги 10 и 11. То же самое можно сказать и про лаг 24. Такая автокорреляция позволяет предположить наличие (ежегодных) сезонных колебаний.

То, что корреляция постоянно положительная говорит о наличии тренда. Все это согласуется с тем, что мы узнали о данных, когда раскладывали их на компоненты.

Также замечу, что синяя граница позволяет оценить статистическую значимость корреляции. Если столбец выходит за ее пределы, то автокорреляция достаточно сильна и ее можно использовать при построении модели.

Сравним полученный выше график с графиком автокорреляционной функции данных о рождаемости.

автокорреляционная функция (ACF) временного ряда по рождаемости

Во-первых, важно отметить, что автокорреляция в данном случае намного слабее. Во-вторых, мы не можем выявить четкой сезонности и тренда.

Моделирование и построение прогноза

На сегодняшнем занятии мы познакомимся с двумя типами моделей: экспоненциальное сглаживание и модель ARMA (и ее более продвинутые версии, ARIMA, SARIMA и SARIMAX).

Экспоненциальное сглаживание

Вновь обратимся к скользящему среднему (см. выше). В этой модели (1) всем предыдущим наблюдениям задавался одинаковый вес и (2) количество таких наблюдений было ограничено (мы называли это размером окна).

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

В модели экспоненциального сглаживания (exponential smoothing) или экспоненциального скользящего среднего мы как раз (1) берем все предыдущие значения и (2) задаем каждому из наблюдений определенный вес и (экспоненциально) уменьшаем этот вес по мере углубления в прошлое.

Приведем формулу.

$$ \hat{y}_{t+1} = \alpha \cdot y_t + (1-\alpha) \cdot \hat{y}_{t} $$

где $ \hat{y}_{t+1} $ — это будущее прогнозное значение, $ y_t $ — истинное значение в текущий период, $\hat{y}_{t}$ — прогнозное значение в текущий период.

Как мы видим, будущее прогнозное значение зависит как от текущего истинного, так и от текущего прогнозного значений. Важность этих значений определяется параметром $\alpha$, который варьируется от 0 до 1. Чем $\alpha$ больше, тем больший вес у истинного наблюдения.

Формула рекурсивна, т.е. каждый раз мы умножаем ($1-\alpha$) на очередное прогнозное значение и так до конца временного ряда.

Практика

На Питоне эту модель не сложно прописать руками.

Для временного ряда, состоящего из 365 наблюдений (весь 1959 год), мы получим 365 прогнозных значений (вплоть до 1 января 1960 года включительно).

Теперь добавим эти данные в исходный датафрейм births.

создание нового столбца в Pandas dataframe

Единственный нюанс, так как фактические значения описывают период с 1 января по 31 декабря 1959 года, а прогнозные со 2 января 1959 года по 1 января 1960, мы не можем просто их соединить. Второй столбец нужно сдвинуть на один день вперед.

добавление новой строки с индексом в виде объекта datetime

Сдвинем второй столбец.

И посмотрим на начало и конец датафрейма.

смещение одного из столбцов датафрейма на один день вперед, первые пять значений
смещение одного из столбцов датафрейма на один день вперед, последние пять значений

Проверим правильность расчетов, найдя последнее прогнозное значение по формуле выше.

$$ \hat{y}_{366} = 0{,}2 \times y_{355} + 0{,}8 \times \hat{y}_{355} = 0{,}2 \times 50 + 0{,}8 \times 45{,}756492 = 46{,}6051936 $$

Результаты совпадают. Теперь выведем фактические и прогнозные значения на графике.

сравнение фактических данных и прогнозных значений в результате экспоненциального сглаживания

Очень советую в качестве упражнения попробовать построить график с несколькими значениями $\alpha$ от 0 до 1.

Модель экспоненциального сглаживания можно усложнить и тогда она будет улавливать тренд и сезонность. Кроме того, усложненные модели способны предсказывать более одного значения (обратите внимание, здесь мы смогли сделать прогноз лишь на один день вперёд).


Работа над ошибками. На видео в формуле экспоненциального сглаживания есть ошибка.

Должно быть.

Как вы видите расчет прогнозного значения в цикле следовало начинать с наблюдения [births['Births'][1], а не [births['Births'][0]. Из-за этого последующие результаты оказались некорректными. В лекции и ноутбуке код исправлен.


Теперь поговорим про модели семейства ARMA.

Модель ARMA

Модель ARMA состоит из двух компонентов.

компоненты модели ARMA: авторегрессия и скользящее среднее

Авторегрессия (autoregressive model, AR) — это регрессия ряда на собственные значения в прошлом. Другими словами, наши признаки в модели обычной регрессии мы заменяем значениями той же переменной, но за предыдущие периоды.

Когда мы прогнозируем значение в период t с помощью данных за предыдущий период (AR(1)), уравнение будет выглядеть следующим образом.

$$ y_t = c + \varphi \cdot y_{t-1} $$

где $c$ — это константа, $\varphi$ — вес модели, $ y_{t-1} $ — значение в период $t-1$.

Количество используемых предыдущих периодов определяется параметром p. Обычно записывается как AR(p).

Модель скользящего среднего (moving average, MA) помогает учесть случайные колебания или отклонения (ошибки) истинного значения от прогнозного. Можно также сказать, что модель скользящего среднего — это авторегрессия на ошибку.

Обратите внимание, что скользящее среднее временного ряда, которое мы рассмотрели выше, и модель скользящего среднего — это разные понятия.

Если использовать ошибку только предыдущего наблюдения, то уравнение будет выглядеть следующим образом.

$$ y_t = \mu + \varphi \cdot \varepsilon_{t-1} $$

где $ \mu $ — это среднее значение временного ряда, $ \varphi $ — вес модели, $ \varepsilon_{t-1} $ — ошибка в период $t-1$.

Такую модель принято называть моделью скользящего среднего с параметром q = 1 или MA(1). Разумеется, параметр q может принимать и другие значения (MA(q)).

Модель ARMA с параметрами (или как еще говорят порядками, orders) p и q или ARMA(p, q) позволяет описать любой стационарный временной ряд.

ARMA предполагает, что в данных отсутствует тренд и сезонность (данные стационарны). Если данные нестационарны, нужно использовать более сложные версии этих моделей:

  • ARIMA, здесь добавляется компонент Integrated (I), который отвечает за удаление тренда (сам процесс называется дифференцированием); и
  • SARIMA, эта модель учитывает сезонность (Seasonality, S)
  • SARIMAX включает еще и внешние или экзогенные факторы (eXogenous factors, отсюда и буква X в названии), которые напрямую не учитываются моделью, но влияют на нее.

Параметров у модели SARIMAX больше. Их полная версия выглядит как SARIMAX(p, d, q) x (P, D, Q, s). В данном случае, помимо известных параметров p и q, у нас появляется параметр d, отвечающий за тренд, а также набор параметров (P, D, Q, s), отвечающих за сезонность.

Теперь давайте воспользуемся моделью SARIMAX для прогнозирования авиаперевозок.

Практика

В первую очередь нужно разбить данные на обучающую и тестовую выборки. Как мы помним, у нас есть данные с января 1949 года по декабрь 1960 года.

Посмотрим на разделение на графике.

разделение данных о перевозках на обучающую и тестовую выборки

Далее нам нужно обучить модель. При обучении модели SARIMAX, самое важное — правильно подобрать гиперпараметры, о которых говорилось выше. Процесс подбора гиперпараметров достаточно сложен, и сегодня мы воспользуемся уже готовыми значениями.

Теперь мы готовы делать прогноз. Вначале сделаем тестовый прогноз, соответствующий периоду тестовой выборки (1960 год), для того, чтобы оценить качество работы модели.

Построим соответствующий график.

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

В целом модель хорошо описывает временной ряд. Мы также можем использовать знакомые нам метрики среднеквадратической ошибки (MSE) и корня среднеквадратической ошибки (RMSE) для оценки качества.

Теперь можно делать прогноз на будущее. Возьмём горизонт равный трем годам (1961, 1962 и 1963 год). Всего должно получиться 36 прогнозных значений.

Посмотрим на прогнозные значения на графике.

фактические данные и прогноз на будущее с помощью модели SARIMAX

Подведем итог

Занятие было насыщенным. Мы узнали, (1) чем временные ряды отличаются от структурных данных, (2) научились анализировать временные ряды с помощью Питона, а также (3) строить графики.

При прогнозировании временных рядов мы (4) использовали модель экспоненциального сглаживания и (5) познакомились с семейством моделей ARMA.

Вопросы для закрепления

Чем структурные/перекрестные данные отличаются от временных рядов?

Посмотреть правильный ответ

Что определяет параметр $ \alpha $ в модели экспоненциального сглаживания?

Посмотреть правильный ответ

Из каких компонентов состоит модель ARMA?

Посмотреть правильный ответ

В рамках вводного курса осталась одна тема, основы нейронных сетей.


Ответы на вопросы

Вопрос. Вы не могли бы более детально рассказать, как подбираются параметры в модели SARIMAX. В частности, как были подобраны параметры (3, 0, 0)x(0, 1, 0, 12)?

Ответ. Параметры SARIMAX можно подобрать с помощью функции auto_arima. Выбор наиболее удачных параметров осуществляется на основе определенного критерия.

По умолчанию используется, так называемый, Akaike Information Criterion или AIC, который рассчитывается для каждой комбинации параметров. Чем ниже AIC модели, тем лучше.

Я привел код auto_arima в конце ноутбука⧉.


Вопрос. У меня уточнение: скажите, там, где мы считаем экспоненциальное сглаживание,

там, может быть, нужно в цикле for i in range(0, len(births['Births'])): поставить начальное значение счетчика = 1: for i in range(1, len(births['Births']))?

Я проверял выкладки в Экселе — и, когда цикл стартует с нуля, получается ошибка. Возможно, это потому, что в начале списка получается задублированное значение первого элемента (мы сначала вручную вносим в список [births['Births'][0]], а потом это же делаем на первой итерации, когда значение счетчика = 0)

Ответ. Да, действительно, первое прогнозное значение мы вносим вручную (оно совпадает с первым фактическим значением), поэтому должно быть

Внес изменения в ноутбук и текст лекции.