Использование модели ARIMA в BigQuery ML для прогнозирования спроса

Давайте сделаем 2-недельный прогноз количества прокатов велосипедов, которые начнутся на одной из велосипедных станций в Гайд-парке, на основе последних шести недель.

Соберите данные для обучения

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

SELECT
   CAST(EXTRACT(date from start_date) AS TIMESTAMP) AS date
   , COUNT(*) AS numrentals
FROM
  `bigquery-public-data`.london_bicycles.cycle_hire
WHERE start_station_name LIKE '%Hyde%'  -- all stations in Hyde Park
GROUP BY date
HAVING date BETWEEN '2015-05-01' AND '2015-06-15'
ORDER BY date

На графике мы видим своего рода недельную тенденцию с повышением арендной платы по выходным:

Обучайте модель ARIMA

Мы можем использовать эти данные для обучения модели ARIMA, сообщая BigQuery, какой столбец является столбцом данных, а какой - столбцом с меткой времени:

CREATE OR REPLACE MODEL ch09eu.numrentals_forecast
OPTIONS(model_type='ARIMA',
        time_series_data_col='numrentals',
        time_series_timestamp_col='date') AS
SELECT
   CAST(EXTRACT(date from start_date) AS TIMESTAMP) AS date
   , COUNT(*) AS numrentals
FROM
  `bigquery-public-data`.london_bicycles.cycle_hire
WHERE start_station_name LIKE '%Hyde%'  -- all stations in Hyde Park
GROUP BY date
HAVING date BETWEEN '2015-05-01' AND '2015-06-15'

После обучения модели мы можем оценить ее с помощью ML.EVALUATE () и просмотреть коэффициенты ARIMA с помощью ML.ARIMA_COEFFICIENTS ().

Прогнозирование

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

SELECT * FROM ML.FORECAST(MODEL ch09eu.numrentals_forecast, 
                  STRUCT(14 AS horizon, 0.9 AS confidence_level))

Границы истории, прогноза и достоверности могут быть построены с использованием:

import matplotlib.pyplot as plt
import pandas as pd
def plot_historical_and_forecast(input_timeseries, forecast_output, timestamp_col_name, data_col_name):
  plt.figure(figsize=(20,6))
  plt.plot(input_timeseries[timestamp_col_name], input_timeseries[data_col_name], label = 'Historical')
  plt.xlabel(timestamp_col_name)
  plt.ylabel(data_col_name)
forecast_output['forecast_timestamp'] = pd.to_datetime(forecast_output['forecast_timestamp'])
  x_data = forecast_output['forecast_timestamp']
  y_data = forecast_output['forecast_value']
  confidence_level = forecast_output['confidence_level'].iloc[0] * 100
  low_CI = forecast_output['confidence_interval_lower_bound']
  upper_CI = forecast_output['confidence_interval_upper_bound']
# Plot the data, set the linewidth, color and transparency of the
  # line, provide a label for the legend
  plt.plot(x_data, y_data, alpha = 1, label = 'Forecast', linestyle='--')
  # Shade the confidence interval
  plt.fill_between(x_data, low_CI, upper_CI, color = '#539caf', alpha = 0.4, label = str(confidence_level) + '% confidence interval')
  # Display legend
  plt.legend(loc = 'upper center', prop={'size': 16})
plot_historical_and_forecast(df, fcst, 'date', 'numrentals')

Это дает:

Но насколько это хорошо по сравнению с тем, что на самом деле произошло во второй половине июня? Мы можем извлечь данные за те дни и сравнить с временными рядами прогноза:

Довольно круто, а?

Прогнозирование ряда серий

Пока что я прогнозировал общий объем аренды для всех велосипедных станций в Гайд-парке. Как мы прогнозируем объем аренды для каждой отдельной станции? Используйте time_series_id_col:

CREATE OR REPLACE MODEL ch09eu.numrentals_forecast
OPTIONS(model_type='ARIMA',
        time_series_data_col='numrentals',
        time_series_timestamp_col='date',
        time_series_id_col='start_station_name') AS
SELECT
   start_station_name
   , CAST(EXTRACT(date from start_date) AS TIMESTAMP) AS date
   , COUNT(*) AS numrentals
FROM
  `bigquery-public-data`.london_bicycles.cycle_hire
WHERE start_station_name LIKE '%Hyde%'  -- all stations in Hyde Park
GROUP BY start_station_name, date
HAVING date BETWEEN '2015-01-01' AND '2015-06-15'

Обратите внимание, что вместо того, чтобы тренировать серию по 45 дней (с 1 мая по 15 июня), я теперь тренируюсь в течение более длительного периода. Это связано с тем, что агрегированные временные ряды, как правило, будут более гладкими и предсказуемыми, чем временные ряды для отдельных станций. Итак, мы должны показать модели более длинную линию тренда.

Теперь это не одна модель ARIMA, а отдельная модель ARIMA для каждого имени станции. Действительно, делая:

SELECT * 
FROM ML.ARIMA_COEFFICIENTS(MODEL ch09eu.numrentals_forecast)
ORDER BY start_station_name

дает нам отдельный набор коэффициентов для каждого start_station_name:

Обратите внимание на кое-что интересное - на каждой из станций есть модели ARIMA разной сложности! Под капотом BigQuery ML выполняет автоматическую настройку гиперпараметров. Хотя модель называется ARIMA, базовый алгоритм фактически включает в себя довольно много наворотов, включая обнаружение аномалий, моделирование эффекта праздника (пользователь должен указать регион праздника), обнаружение / моделирование сезонности и моделирование тенденций. Кроме того, разные временные ряды обучаются параллельно.

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

SELECT 
  start_station_name,
  forecast_timestamp, forecast_value
FROM ML.FORECAST(MODEL ch09eu.numrentals_forecast, 
                  STRUCT(3 AS horizon, 0.9 AS confidence_level))
ORDER By start_station_name, forecast_timestamp

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

В полной записной книжке на GitHub есть графики прогнозов по станциям.

Оценка модели может помочь вам предугадать, на каких станциях модель будет лучше (чем ниже дисперсия с поправкой на сезонность, тем легче ее предсказать, и, следовательно, тем лучше должна быть модель - вы не можете использовать здесь AIC, потому что AIC разные временные ряды не сопоставимы):

SELECT * FROM ML.EVALUATE(MODEL ch09eu.numrentals_forecast)
ORDER BY variance DESC

По результатам мы ожидаем, что прогнозы на Hyde Park Corner будут наихудшими, а на Knightsbridge - наилучшими:

Наслаждаться!

Следующие шаги

  1. Просмотрите полную записную книжку на GitHub.
  2. Чтобы узнать больше о BigQuery ML, прочтите главу 9 BigQuery: The Definitive Guide. Книга периодически пополняется этими сообщениями в блоге, так что она остается окончательной.

Спасибо Си Ченгу и Амиру Хормати за полезные предложения