Потребление энергии (энергопотребление) Прогноз набора данных (4): Saving Prophet

Python

предисловие

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

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

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

Результаты нашего пророка такие же «хорошие», как и предсказания kaggle (по сравнению с очень плохими у lghtgbm).

Но так ли слаба суперсила Prophet, крупной компании Facebook?

Код для спасения пророка

Для глубокого обучения никакая нормализация не заставит вашу модель улететь.

Для древовидных моделей выбросы иногда могут сделать ваши функции необъяснимо важными.

Кажется, нет никаких особых соображений для prohet и нет необходимости очищать данные.

Но проблема часто скрывается именно в нем.

читать данные

Код остается прежним.

import pandas as pd
from fbprophet import Prophet, make_holidays
from sklearn.metrics import mean_absolute_error
from fbprophet.plot import add_changepoints_to_plot


file = 'data/PJME_hourly.csv'
raw_df = pd.read_csv(file)
print(raw_df.head(5))

Преобразование строкового времени в формат метки времени pandas и предварительный просмотр головы и хвоста.

dt_format = '%Y-%m-%d %H:%M:%S'
raw_df['Datetime'] = pd.to_datetime(raw_df['Datetime'], format=dt_format)
raw_df.rename({'PJME_MW': 'y', 'Datetime': 'ds'}, axis=1, inplace=True)
print(raw_df.tail(5))
print(raw_df.describe())

Период времени можно увидеть с 2002 по 2018 год, и порядок кажется правильным.

                      ds        y
8734 2002-01-01 01:00:00  30393.0
8735 2002-01-01 02:00:00  29265.0
8736 2002-01-01 03:00:00  28357.0
8737 2002-01-01 04:00:00  27899.0
8738 2002-01-01 05:00:00  28057.0
                        ds        y
140250 2018-08-02 20:00:00  44057.0
140251 2018-08-02 21:00:00  43256.0
140252 2018-08-02 22:00:00  41552.0
140253 2018-08-02 23:00:00  38500.0
140254 2018-08-03 00:00:00  35486.0

Чтобы быть в безопасности, мы сортируем временную шкалу.

raw_df = raw_df.sort_values(by=['ds']) # sort by time
print(raw_df.tail(5))
print(raw_df.describe())

Разделите тестовый набор и тренировочный набор в соответствии с моментом времени

split_dt = pd.Timestamp('2015-01-01 00:00:00')
train_df = raw_df[raw_df['ds'] < split_dt]
test_df = raw_df[raw_df['ds'] >= split_dt]

моделирование пророка

Здесь мы по-прежнему используем параметры по умолчанию.

model = Prophet()
model= model.fit(train_df)
y_hat  = model.predict(test_df)
y_test = model.predict(test_df)
fig = model.plot(y_test)
a = add_changepoints_to_plot(fig.gca(), model, y_test)
print(mean_absolute_error(test_df['y'].values, y_test['yhat']))
model.plot_components(y_test)

результат

Мы видим, что результат ошибки оказался 3105. По сравнению с моделью из нашей второй статьи и 5183 от Kaggle, она намного лучше.

А наш код практически не изменился, и настройки параметров нет?

3105.4775855473995

Анализ причин

На самом деле причина улучшения очень проста, в данных есть ошибки! !

На самом деле это не баг, это должны быть грязные данные, и они спрятаны немного глубоко. Как правило, мы предварительно просматриваем начало (5) и хвост (5) и видим, что порядок одинаков, по умолчанию данные расположены в хронологическом порядке. Вообще-то нет!

При предварительном просмотре первых 30 строк данных мы обнаружим, что даты расположены в обратном порядке. И необъяснимое 1 января было добавлено посередине.

Незаметное предложение sort_value в нашем коде значительно уменьшает количество ошибок.

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

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

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

Datetime,PJME_MW
2002-12-31 01:00:00,26498.0
2002-12-31 02:00:00,25147.0
2002-12-31 03:00:00,24574.0
2002-12-31 04:00:00,24393.0
2002-12-31 05:00:00,24860.0
2002-12-31 06:00:00,26222.0
2002-12-31 07:00:00,28702.0
2002-12-31 08:00:00,30698.0
2002-12-31 09:00:00,31800.0
2002-12-31 10:00:00,32359.0
2002-12-31 11:00:00,32371.0
2002-12-31 12:00:00,31902.0
2002-12-31 13:00:00,31126.0
2002-12-31 14:00:00,30368.0
2002-12-31 15:00:00,29564.0
2002-12-31 16:00:00,29098.0
2002-12-31 17:00:00,30308.0
2002-12-31 18:00:00,34017.0
2002-12-31 19:00:00,34195.0
2002-12-31 20:00:00,32790.0
2002-12-31 21:00:00,31336.0
2002-12-31 22:00:00,29887.0
2002-12-31 23:00:00,28483.0
2003-01-01 00:00:00,27008.0
2002-12-30 01:00:00,27526.0
2002-12-30 02:00:00,26600.0
2002-12-30 03:00:00,26241.0
2002-12-30 04:00:00,26213.0
2002-12-30 05:00:00,26871.0

Расширенная конфигурация параметров пророка

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

Добавьте информацию о празднике

Например, мы можем добавить информацию о праздниках США. Информация о празднике будет передана в параметр праздника пророка.

holidays = make_holidays.make_holidays_df(range(2002, 2018, 1), 'US')

индивидуальные условия

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

  • Например, цикл недели составляет 7 дней, но первые 5 дней рабочие, а последние два дня выходные.
  • Или сутки можно разделить на день и ночь, а их цикл все равно 1 день.
  • В году могут быть низкие сезоны и пиковые сезоны, например, лето может быть пиковым периодом потребления электроэнергии (холодильное оборудование), мы можем разделить его так
raw_df['on_season'] = (raw_df['ds'].dt.month > 4) | (raw_df['ds'].dt.month < 8)
raw_df['off_season'] = ~(raw_df['ds'].dt.month > 4) | (raw_df['ds'].dt.month < 8)


raw_df['night'] = (raw_df['ds'].dt.hour > 20) | (raw_df['ds'].dt.hour < 8)
raw_df['daylight'] = ~(raw_df['ds'].dt.hour > 20) | (raw_df['ds'].dt.hour < 8)

raw_df['weekend'] = raw_df['ds'].dt.week > 5
raw_df['workday'] = ~raw_df['weekend']

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

Мы можем установить для модели по умолчанию yearly_seasonality, weekly_seasonality и daily_seasonality значение False, а затем добавить собственный определенный период или наложить определенные нами условия. Также для каждого цикла мы можем определить его вес (prior_scale).

model = Prophet(
    holidays=holidays,
    changepoint_prior_scale=0.5,
    holidays_prior_scale=10,
    seasonality_prior_scale=10,
    yearly_seasonality=False,
    weekly_seasonality=False,
    daily_seasonality=False)
model.add_country_holidays(country_name='US')
model.add_seasonality(name='half_daily',period=0.5,fourier_order=12)
model.add_seasonality(name='daylight_daily',period=1,fourier_order=24,condition_name='daylight')
model.add_seasonality(name='night_daily',period=1,fourier_order=24,condition_name='night')
model.add_seasonality(name='weekend_weekly',period=7,fourier_order=14,prior_scale=10,condition_name='weekend')
model.add_seasonality(name='workday_weekly',period=7,fourier_order=14,prior_scale=10,condition_name='workday')
model.add_seasonality(name='on_season_half_year',period=182.625,fourier_order=24,prior_scale=10,condition_name='on_season')
model.add_seasonality(name='off_season_half_year',period=182.625,fourier_order=24,prior_scale=10,condition_name='off_season')
model.add_seasonality(name='on_season_year',period=365.25,fourier_order=24,prior_scale=10,condition_name='on_season')
model.add_seasonality(name='off_season_year',period=365.25,fourier_order=24,prior_scale=10,condition_name='off_season')

Текущий результат:

3043.2366637873324

Ошибка уменьшена по сравнению с параметром по умолчанию.

Прикрепляем еще результаты разложения:

Суммировать

Эта статья успешно решает проблему, возникающую при моделировании пророков, уменьшая ошибку с более чем 5000 до более чем 3000. Из этой статьи вы можете узнать:

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