Большинство из нас слышало бы о новой шумихе на рынке, то есть о криптовалюте. Многие из нас тоже вложили бы деньги в свои монеты. Но безопасно ли вкладывать деньги в такую ​​нестабильную валюту? Как мы можем гарантировать, что инвестирование в эти монеты сейчас обязательно принесет здоровую прибыль в будущем? Мы не можем быть уверены в этом, но можем точно рассчитать приблизительную стоимость на основе предыдущих цен. Модели временных рядов - это один из способов их предсказать.

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

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

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

Давайте начнем!

Оглавление

  • Понимание постановки проблемы и набора данных
  • Установка библиотеки (statsmodels)
  • Метод 1. Начните с наивного подхода
  • Метод 2 - Простое среднее
  • Метод 3 - скользящее среднее
  • Метод 4 - однократное экспоненциальное сглаживание
  • Метод 5 - метод линейного тренда Холта
  • Метод 6 - зимний сезонный метод Холта
  • Метод 7 - ARIMA

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

Нам предоставляется задача временных рядов, включающая прогнозирование количества пассажиров JetRail, нового высокоскоростного железнодорожного сообщения от Unicorn Investors. Нам предоставлены данные за 2 года (август 2012 г. - сентябрь 2014 г.), и, используя эти данные, мы должны спрогнозировать количество пассажиров пригородных поездов на следующие 7 месяцев.

Приступим к работе с набором данных, загруженным по указанной выше ссылке. В этой статье я работаю только с набором данных поезда.

import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
#Importing data
df = pd.read_csv('train.csv')
#Printing head
df.head()

#Printing tail
df.tail()

Как видно из приведенных выше заявлений для печати, нам даны данные за 2 года (2012–2014 гг.) На почасовом уровне с количеством пассажиров, путешествующих пригородных поездов, и нам нужно оценить количество пассажиров на будущее.

В этой статье я ежедневно разбиваю и объединяю набор данных, чтобы объяснить различные методы.

  • Подмножество набора данных из (август 2012 г. - декабрь 2013 г.)
  • Создание обучающего и тестового файла для моделирования. Первые 14 месяцев (август 2012 г. - октябрь 2013 г.) используются в качестве данных обучения, а следующие 2 месяца (ноябрь 2013 г. - декабрь 2013 г.) - как данные тестирования.
  • Ежедневное агрегирование набора данных
#Subsetting the dataset
#Index 11856 marks the end of year 2013
df = pd.read_csv('train.csv', nrows = 11856)

#Creating train and test set 
#Index 10392 marks the end of October 2013 
train=df[0:10392] 
test=df[10392:]

#Aggregating the dataset at daily level
df.Timestamp = pd.to_datetime(df.Datetime,format='%d-%m-%Y %H:%M') 
df.index = df.Timestamp 
df = df.resample('D').mean()
train.Timestamp = pd.to_datetime(train.Datetime,format='%d-%m-%Y %H:%M') 
train.index = train.Timestamp 
train = train.resample('D').mean() 
test.Timestamp = pd.to_datetime(test.Datetime,format='%d-%m-%Y %H:%M') 
test.index = test.Timestamp 
test = test.resample('D').mean()

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

#Plotting data
train.Count.plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14)
test.Count.plot(figsize=(15,8), title= 'Daily Ridership', fontsize=14)
plt.show()

Установка библиотеки (statsmodels)

Библиотека, которую я использовал для прогнозирования временных рядов, - это statsmodels. Вам необходимо установить его, прежде чем применять некоторые из указанных подходов. statsmodels может быть уже установлен в вашей среде Python, но он не поддерживает методы прогнозирования. Мы клонируем его из их репозитория и устанавливаем с использованием исходного кода. Следуй этим шагам :-

  1. Используйте pip freeze, чтобы проверить, установлен ли он в вашей среде.
  2. Если он уже присутствует, удалите его с помощью «conda remove statsmodels».
  3. Клонируйте репозиторий statsmodels с помощью «git clone git: //github.com/statsmodels/statsmodels.git». Перед клонированием инициализируйте Git с помощью «git init».
  4. Измените каталог на statsmodels, используя «cd statsmodels»
  5. Создайте установочный файл с помощью python setup.py build.
  6. Установите его с помощью «python setup.py install»
  7. Выйдите из bash / терминала
  8. Перезапустите bash / terminal в своей среде, откройте python и выполните «from statsmodels.tsa.api import ExponentialSmoothing» для проверки.

Метод 1: начните с наивного подхода

Рассмотрим график, приведенный ниже. Предположим, что по оси ординат отложена цена монеты, а по оси абсцисс отложено время (дни).

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

Теперь реализуем метод Naive для прогнозирования цен на тестовые данные.

dd= np.asarray(train.Count)
y_hat = test.copy()
y_hat['naive'] = dd[len(dd)-1]
plt.figure(figsize=(12,8))
plt.plot(train.index, train['Count'], label='Train')
plt.plot(test.index,test['Count'], label='Test')
plt.plot(y_hat.index,y_hat['naive'], label='Naive Forecast')
plt.legend(loc='best')
plt.title("Naive Forecast")
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели на наборе тестовых данных.

from sklearn.metrics import mean_squared_error
from math import sqrt
rms = sqrt(mean_squared_error(test.Count, y_hat.naive))
print(rms)

RMSE = 43.9164061439

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

Метод 2: - Простое среднее

Рассмотрим график, приведенный ниже. Предположим, что по оси ординат отложена цена монеты, а по оси абсцисс отложено время (дни).

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

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

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

y_hat_avg = test.copy()
y_hat_avg['avg_forecast'] = train['Count'].mean()
plt.figure(figsize=(12,8))
plt.plot(train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['avg_forecast'], label='Average Forecast')
plt.legend(loc='best')
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.avg_forecast))
print(rms)

RMSE = 109.545990803

Мы видим, что эта модель не улучшила нашу оценку. Следовательно, мы можем сделать вывод из оценки, что этот метод работает лучше всего, когда среднее значение за каждый период времени остается постоянным. Хотя оценка наивного метода лучше, чем у метода «Среднее», это не означает, что наивный метод лучше, чем метод «Среднее» для всех наборов данных. Мы должны шаг за шагом переходить к каждой модели и проверять, улучшает ли она нашу модель или нет.

Метод 3 - скользящее среднее

Рассмотрим график, приведенный ниже. Предположим, что по оси ординат отложена цена монеты, а по оси абсцисс отложено время (дни).

Из графика можно сделать вывод, что цены на монету несколько периодов назад выросли с большим отрывом, но сейчас они стабильны. Часто нам предоставляют набор данных, в котором цены / продажи объекта резко выросли / снизились несколько периодов времени назад. Чтобы использовать предыдущий метод среднего значения, мы должны использовать среднее значение всех предыдущих данных, но использование всех предыдущих данных звучит неправильно.

Использование цен начального периода сильно повлияет на прогноз на следующий период. Поэтому в качестве улучшения по сравнению с простым средним мы возьмем среднее значение цен только за последние несколько периодов времени. Очевидно, здесь думают, что имеют значение только недавние значения. Такой метод прогнозирования, который использует окно временного периода для вычисления среднего, называется методом скользящего среднего. Расчет скользящего среднего включает то, что иногда называют «скользящим окном» размера n.

Используя простую модель скользящего среднего, мы прогнозируем следующее значение (я) во временном ряду на основе среднего фиксированного конечного числа «p» предыдущих значений. Таким образом, для всех i ›p

Скользящее среднее действительно может быть довольно эффективным, особенно если вы выберете правильный p для ряда.

y_hat_avg = test.copy()
y_hat_avg['moving_avg_forecast'] = train['Count'].rolling(60).mean().iloc[-1]
plt.figure(figsize=(16,8))
plt.plot(train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['moving_avg_forecast'], label='Moving Average Forecast')
plt.legend(loc='best')
plt.show()

Мы выбрали данные только за последние 2 месяца. Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.moving_avg_forecast))
print(rms)
RMSE = 46.7284072511

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

Усовершенствованием метода скользящего среднего является метод взвешенного скользящего среднего. В методе скользящего среднего, как показано выше, мы одинаково взвешиваем прошлые n наблюдений. Но мы можем столкнуться с ситуациями, когда каждое из наблюдений прошлого 'n' по-разному влияет на прогноз. Такой метод, который по-разному оценивает прошлые наблюдения, называется методом взвешенного скользящего среднего.

Взвешенное скользящее среднее - это скользящее среднее, в котором значениям в скользящем окне присваиваются разные веса, обычно так, чтобы более свежие точки имели значение больше.

Вместо выбора размера окна требуется список весов (в сумме должен быть равен 1). Например, если мы выберем [0,40, 0,25, 0,20, 0,15] в качестве весов, мы дадим 40%, 25%, 20% и 15% последним 4 точкам соответственно.

Метод 4 - Простое экспоненциальное сглаживание

После того, как мы разобрались с описанными выше методами, мы можем заметить, что и простое среднее, и средневзвешенное скользящее среднее лежат на совершенно противоположных концах. Нам понадобится что-то среднее между этими двумя крайними подходами, которое учитывает все данные при различном взвешивании точек данных. Например, может быть разумным придавать больший вес более свежим наблюдениям, чем наблюдениям из далекого прошлого. Техника, работающая на этом принципе, называется простым экспоненциальным сглаживанием. Прогнозы рассчитываются с использованием средневзвешенных значений, где веса экспоненциально уменьшаются по мере того, как наблюдения происходят из более далекого прошлого, наименьшие веса связаны с самыми старыми наблюдениями:

где 0≤ α ≤1 - параметр сглаживания.

Прогноз на один шаг вперед для времени T + 1 представляет собой средневзвешенное значение всех наблюдений в ряду y1,…, yT. Скорость уменьшения веса контролируется параметром α.

Если вы посмотрите на него достаточно долго, вы увидите, что ожидаемое значение ŷx является суммой двух произведений: α⋅yt и (1 − α) ⋅ŷ t-1.

Следовательно, это также можно записать как:

По сути, у нас есть взвешенная скользящая средняя с двумя весами: α и 1 − α.

Как мы видим, 1 − α умножается на предыдущее ожидаемое значение ŷ x − 1, что делает выражение рекурсивным. Вот почему этот метод называется Экспоненциальный. Прогноз в момент времени t + 1 равен средневзвешенному значению между самым последним наблюдением yt и самым последним прогнозом ŷ t | t − 1.

from statsmodels.tsa.api import ExponentialSmoothing, SimpleExpSmoothing, Holt
y_hat_avg = test.copy()
fit2 = SimpleExpSmoothing(np.asarray(train['Count'])).fit(smoothing_level=0.6,optimized=False)
y_hat_avg['SES'] = fit2.forecast(len(test))
plt.figure(figsize=(16,8))
plt.plot(train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['SES'], label='SES')
plt.legend(loc='best')
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.SES))
print(rms)

RMSE = 43.3576252252

Мы видим, что реализация простой экспоненциальной модели с альфой, равной 0,6, до сих пор генерирует лучшую модель. Мы можем настроить параметр, используя набор проверки, чтобы создать еще лучшую Простую экспоненциальную модель.

Метод 5 - метод линейного тренда Холта

Теперь мы изучили несколько методов прогнозирования, но видим, что эти модели не работают с данными с большим разбросом. Учтите, что цена биткойна растет.

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

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

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

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

import statsmodels.api as sm
sm.tsa.seasonal_decompose(train.Count).plot()
result = sm.tsa.stattools.adfuller(train.Count)
plt.show()

Из полученных графиков видно, что этот набор данных имеет тенденцию к увеличению. Следовательно, мы можем использовать линейный тренд Холта для прогнозирования будущих цен.

Холт расширил простое экспоненциальное сглаживание, чтобы можно было прогнозировать данные с трендом. Это не что иное, как экспоненциальное сглаживание, применяемое как к уровню (среднее значение в ряду), так и к тренду. Чтобы выразить это в математической записи, нам теперь нужны три уравнения: одно для уровня, одно для тренда и одно для объединения уровня и тренда, чтобы получить ожидаемый прогноз ŷ

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

Как и в случае простого экспоненциального сглаживания, уравнение уровня здесь показывает, что это средневзвешенное значение наблюдения и прогноз на один шаг вперед внутри выборки. Уравнение тенденции показывает, что это средневзвешенное значение оцененного тренда в момент времени t на основе ℓ (t) − (t − 1) и b (t − 1), предыдущая оценка тенденции.

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

y_hat_avg = test.copy()

fit1 = Holt(np.asarray(train['Count'])).fit(smoothing_level = 0.3,smoothing_slope = 0.1)
y_hat_avg['Holt_linear'] = fit1.forecast(len(test))

plt.figure(figsize=(16,8))
plt.plot(train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['Holt_linear'], label='Holt_linear')
plt.legend(loc='best')
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.Holt_linear))
print(rms)
RMSE = 43.0562596115

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

Метод 6 - Метод Холта-Винтерса

Итак, давайте введем новый термин, который будет использоваться в этом алгоритме. Рассмотрим отель, расположенный на горной станции. В летний сезон его посещают много людей, тогда как в остальное время посетителей сравнительно меньше. Следовательно, прибыль, полученная владельцем в летний сезон, будет намного выше, чем в любое другое время года. Этот образец будет повторяться каждый год. Такое повторение называется сезонностью. Наборы данных, которые показывают аналогичный набор закономерностей через фиксированные интервалы времени, страдают от сезонности.

Вышеупомянутые модели не учитывают сезонность набора данных при прогнозировании. Следовательно, нам нужен метод, который учитывает как тенденцию, так и сезонность для прогнозирования будущих цен. Одним из таких алгоритмов, который мы можем использовать в таком сценарии, является метод Холта Винтера. Идея тройного экспоненциального сглаживания (Holt’s Winter) заключается в применении экспоненциального сглаживания к сезонным компонентам в дополнение к уровню и тренду.

Использование зимнего метода Холта будет лучшим вариантом среди остальных моделей из-за фактора сезонности. Сезонный метод Холта-Винтерса включает уравнение прогноза и три уравнения сглаживания - одно для уровня ℓt, одно для тренда bt и одно для сезонной составляющей, обозначенной как st, с параметрами сглаживания α, β и γ.

где s - длина сезонного цикла для 0 ≤ α ≤ 1, 0 ≤ β ≤ 1 и 0 ≤ γ ≤ 1.

Уравнение уровня показывает средневзвешенное значение между сезонно скорректированным наблюдением и несезонным прогнозом для времени t. Уравнение тенденции идентично линейному методу Холта. Сезонное уравнение показывает средневзвешенное значение между текущим сезонным индексом и сезонным индексом того же сезона в прошлом году (т. Е. S периодов времени назад).

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

y_hat_avg = test.copy()
fit1 = ExponentialSmoothing(np.asarray(train['Count']) ,seasonal_periods=7 ,trend='add', seasonal='add',).fit()
y_hat_avg['Holt_Winter'] = fit1.forecast(len(test))
plt.figure(figsize=(16,8))
plt.plot( train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['Holt_Winter'], label='Holt_Winter')
plt.legend(loc='best')
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.Holt_Winter))
print(rms)

RMSE = 23.9614925662

Из графика видно, что отображение правильного тренда и сезонности дает гораздо лучшее решение. Мы выбрали сезонный_период = 7, поскольку данные повторяются еженедельно. Остальные параметры можно настроить согласно набору данных. При построении этой модели я использовал параметры по умолчанию. Вы можете настроить параметры, чтобы получить лучшую модель.

Метод 7 - ARIMA

Еще одна распространенная модель временных рядов, очень популярная среди специалистов по данным, - это ARIMA. Это означает Авторегрессионное интегрированное скользящее среднее. В то время как модели экспоненциального сглаживания основывались на описании тренда и сезонности данных, модели ARIMA стремятся описать корреляции в данных друг с другом. Улучшение ARIMA - это Seasonal ARIMA. Он учитывает сезонность набора данных, как и метод Холта Винтера. Вы можете узнать больше о моделях ARIMA и Seasonal ARIMA и их предварительной обработке из статей (1) и (2).

y_hat_avg = test.copy()
fit1 = sm.tsa.statespace.SARIMAX(train.Count, order=(2, 1, 4),seasonal_order=(0,1,1,7)).fit()
y_hat_avg['SARIMA'] = fit1.predict(start="2013-11-1", end="2013-12-31", dynamic=True)
plt.figure(figsize=(16,8))
plt.plot( train['Count'], label='Train')
plt.plot(test['Count'], label='Test')
plt.plot(y_hat_avg['SARIMA'], label='SARIMA')
plt.legend(loc='best')
plt.show()

Теперь мы рассчитаем RMSE, чтобы проверить точность нашей модели.

rms = sqrt(mean_squared_error(test.Count, y_hat_avg.SARIMA))
print(rms)

RMSE = 26.035582877

Мы видим, что использование Seasonal ARIMA позволяет получить такое же решение, как и Holt’s Winter. Мы выбрали параметры согласно графикам ACF и PACF. Вы можете узнать о них больше по ссылкам, указанным выше. Если у вас возникнут трудности с поиском параметров модели ARIMA, вы можете использовать auto.arima, реализованный на языке R. Замену auto.arima в Python можно посмотреть здесь.

Мы можем сравнить эти модели на основе их оценок RMSE.

Конечные заметки

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

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

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

Считаете ли вы эту статью полезной? Пожалуйста, поделитесь своим мнением / мыслями в разделе комментариев ниже.

Первоначально опубликовано на www.analyticsvidhya.com 8 февраля 2018 г.