Решение для демонстрации обслуживания API модели Prophet в Интернете с помощью Flask. Prophet - библиотека Python с открытым исходным кодом, разработанная Facebook для прогнозирования данных временных рядов.

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

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

Когда я нашел на GitHub и оценил библиотеку Python Prophet для прогнозирования будущего, я был впечатлен ее простотой и практичностью. Prophet - библиотека прогнозов с открытым исходным кодом, разработанная Facebook.

Я поделюсь образцом записной книжки Python с реализацией прогноза Prophet и покажу, как сохранять / загружать модель Prophet и обслуживать ее через Flask API.

Исходный код и данные доступны в моем репо на GitHub.

Во-первых, вам нужно импортировать библиотеку Prophet:

import pandas as pd
import matplotlib.pyplot as plt
from fbprophet import Prophet
%matplotlib inline

Если Prophet не установлен в вашей среде, вам необходимо установить его. Я устанавливал его в Ubuntu, работающем в контейнере Docker. Не удалось установить с помощью pip. Но мне удалось установить с помощью conda:

conda install gcc
conda install -c conda-forge fbprophet

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

df = pd.read_csv('Dow Jones Iron & Steel Historical Data.csv')
df = df[['Date', 'Price']].dropna()
df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')
daily_df = df.resample('D').mean()
d_df = daily_df.reset_index().dropna()

Prophet оперирует столбцами ds / y, мы должны переименовать столбцы во фрейме данных:

d_df.columns = ['ds', 'y']
fig = plt.figure(facecolor='w', figsize=(20, 6))
plt.plot(d_df.ds, d_df.y)

Данные о ценах на железо / сталь, которые мы собираемся использовать для обучения модели Пророка:

А вот и ключевая часть - обучение модели Пророка:

m = Prophet()
m.fit(d_df)
future = m.make_future_dataframe(periods=90)
forecast = m.predict(future)
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail()

Обучение модели выполняется путем вызова функции fit и передачи кадра данных Pandas. Прогнозирование будущего выполняется функцией прогноз и переданным параметром, описывающим, сколько дней в будущем нужно предсказать (90 дней в приведенном выше примере). Prophet возвращает фрейм данных с различными параметрами для описания прогноза. Один из наиболее важных:

  1. ds - дата прогноза
  2. yhat - прогнозируемое значение на заданную дату
  3. yhat_lower - нижняя граница прогноза на заданную дату
  4. yhat_uppet - верхняя граница прогноза на заданную дату

Вызов функции plot для модели Prophet отображает, как модель была обучена в соответствии с данными обучения (черные точки - данные обучения, синяя линия - значение прогноза, голубая область - границы прогноза):

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

from datetime import datetime, timedelta
fig1 = m.plot(forecast)
#datenow = datetime.now()
datenow = datetime(2019, 7, 2)
dateend = datenow + timedelta(days=90)
datestart = dateend - timedelta(days=450)
plt.xlim([datestart, dateend])
plt.title("Iron/steel forecast", fontsize=20)
plt.xlabel("Day", fontsize=20)
plt.ylabel("Iron/steel price", fontsize=20)
plt.axvline(datenow, color="k", linestyle=":")
plt.show()

Это помогает яснее увидеть прогноз на 90 дней. В прогнозе цены мы видим тенденцию к снижению:

Существует простой способ распечатать значения прогноза, получая доступ к последним 90 дням из фрейма данных прогноза:

forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']][-90:]

Для оценки модели полезно отображать изученные тенденции:

fig2 = m.plot_components(forecast)

Пророк узнает, что цена обычно снижается с марта по октябрь.

Вы должны проверить, какова ожидаемая ошибка при прогнозировании на определенное количество дней. Это называется перекрестной проверкой модели:

from fbprophet.diagnostics import cross_validation, performance_metrics
df_cv = cross_validation(m, horizon='90 days')
df_p = performance_metrics(df_cv)
df_p.head(5)

Результат:

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

from fbprophet.plot import plot_cross_validation_metric
fig3 = plot_cross_validation_metric(df_cv, metric='mape')

Он показывает, что 10-дневный прогноз приводит к ошибке около 10%, а затем ошибка возрастает примерно до 18%:

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

import pickle
with open('forecast_model.pckl', 'wb') as fout:
    pickle.dump(m, fout)
with open('forecast_model.pckl', 'rb') as fin:
    m2 = pickle.load(fin)

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

Flask отлично работает, чтобы представить модель Prophet внешнему миру через REST API. Импортировать библиотеку Flask:

from flask import Flask, jsonify, request
from flask_cors import CORS, cross_origin

Вызовите прогноз внутри функции с аннотацией Flask:

app = Flask(__name__)
CORS(app)
@app.route("/katana-ml/api/v1.0/forecast/ironsteel", methods=['POST'])
def predict():
    horizon = int(request.json['horizon'])
    
    future2 = m2.make_future_dataframe(periods=horizon)
    forecast2 = m2.predict(future2)
    
    data = forecast2[['ds', 'yhat', 'yhat_lower', 'yhat_upper']][-horizon:]
    
    ret = data.to_json(orient='records', date_format='iso')
    
    return ret
# running REST interface, port=3000 for direct test
if __name__ == "__main__":
    app.run(debug=False, host='0.0.0.0', port=3000)

Пример вызова REST API через Postman. Параметр горизонта прогноза передается в API, и мы получаем ответ JSON с данными прогноза:

Исходный код и образцы данных доступны в моем репозитории GitHub.