Глобальное локальное моделирование

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

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

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

Сначала загружаем данные:

if "google.colab" in str(get_ipython()):
    # Удаление предустановленных пакетов из Colab для избежания конфликтов
    !pip uninstall -y torch notebook notebook_shim tensorflow tensorflow-datasets prophet torchaudio torchdata torchtext torchvision
    !pip install git+https://github.com/ourownstory/neural_prophet.git # может занять некоторое время
    #!pip install neuralprophet # намного быстрее, но может не иметь последних обновлений/исправлений ошибок

import pandas as pd
from neuralprophet import NeuralProphet, set_log_level
from neuralprophet import set_random_seed
import numpy as np

set_random_seed(10)
set_log_level("ERROR", "INFO")
data_location = "https://raw.githubusercontent.com/ourownstory/neuralprophet-data/main/datasets/"
df_ercot = pd.read_csv(data_location + "multivariate/load_ercot_regions.csv")
df_ercot.head()
ds
COAST
EAST
FAR_WEST
NORTH
NORTH_C
SOUTHERN
SOUTH_C
WEST

0

2004-01-01 01:00:00

7225.09

877.79

1044.89

745.79

7124.21

1660.45

3639.12

654.61

1

2004-01-01 02:00:00

6994.25

850.75

1032.04

721.34

6854.58

1603.52

3495.16

639.88

2

2004-01-01 03:00:00

6717.42

831.63

1021.10

699.70

6639.48

1527.99

3322.70

623.42

3

2004-01-01 04:00:00

6554.27

823.56

1015.41

691.84

6492.39

1473.89

3201.72

613.49

4

2004-01-01 05:00:00

6511.19

823.38

1009.74

686.76

6452.26

1462.76

3163.74

613.32

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

regions = list(df_ercot)[1:]

Глобальные модели можно активировать, когда входные данные df функции имеют дополнительную колонку «ID», которая идентифицирует различные временные ряды (помимо типичной колонки «ds», содержащей временные метки, и колонки «y», содержащей наблюдаемые значения временного ряда). В нашем примере мы выбираем данные за трехлетний интервал (с 2004 по 2007 год).

df_global = pd.DataFrame()
for col in regions:
    aux = df_ercot[["ds", col]].copy(deep=True)  # выберите столбец, связанный с регионом
    aux = aux.iloc[:26301, :].copy(deep=True)  # выберите данные до строки 26301 (временные метки с 2004 по 2007 год)
    aux = aux.rename(columns={col: "y"})  # переименуйте столбец данных в 'y', что совместимо с Neural Prophet
    aux["ID"] = col
    df_global = pd.concat((df_global, aux))

Мы изменим тенденцию для СЕВЕРА и сезонность для ПОБЕРЕЖЬЯ.

df_global["y"] = (
    np.where(df_global["ID"] == "COAST", -df_global["y"], df_global["y"])  # если регион COAST, инвертируем значения столбца "y"
    + 2 * df_global.loc[df_global["ID"] == "COAST", "y"].mean()  # добавляем удвоенное среднее значение столбца "y" для COAST
)
df_global["y"] = np.where(df_global["ID"] == "NORTH", df_global["y"] + 0.1 * df_global.index, df_global["y"])  # если регион NORTH, добавляем 0.1 * индекс строки к значениям столбца "y"

df_global.loc[df_global["ID"] == "NORTH"].plot()  # визуализируем данные для региона NORTH
df_global.loc[df_global["ID"] == "COAST"].plot()  # визуализируем данные для региона COAST

Глобальное моделирование

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

m = NeuralProphet(
    trend_global_local="global",  # используем глобальную модель для тренда
    season_global_local="global",  # используем глобальную модель для сезонности
    changepoints_range=0.8,  # доля данных для поиска точек изменений
    epochs=20,  # количество эпох обучения
    trend_reg=5,  # коэффициент регуляризации для тренда
)
m.set_plotting_backend("plotly-static")  # устанавливаем бэкенд для визуализации графиков

Когда входными данными для функции split_df является pd.DataFrame со столбцом ID, тренировочные и валидационные данные предоставляются в аналогичном формате. Для глобальных моделей входные данные обычно разделяются в соответствии с долей времени, охватывающей все временные ряды (по умолчанию, когда есть более одного ID и когда local_split=False). Если пользователь хочет разделить каждый временной ряд локально, параметр local_split должен быть установлен в значение True. В этом примере мы разделим наши данные на тренировочные и тестовые (с 33% долей тестовой выборки - 2 года на обучение и 1 год на тестирование).

df_train, df_test = m.split_df(df_global, valid_p=0.33, local_split=True)  # разделяем данные на тренировочный и тестовый наборы
print(df_train.shape, df_test.shape)  # выводим размеры тренировочного и тестового наборов

После создания объекта NeuralProphet, модель может быть создана путем вызова функции fit

metrics = m.fit(df_train, freq="H")  # обучаем модель на тренировочных данных с частотой "H" (час)

Убедитесь, что вы предоставляете данные, идентифицированные с ключами, связанными с соответствующими временными рядами поездов. Таким образом, подходящие параметры нормализации данных используются в процедурах после подгонки (т.е.,predict, test).

future = m.make_future_dataframe(df_test, n_historic_predictions=True)  # создаем будущие даты на основе тестовых данных
forecast = m.predict(future)  # делаем прогноз на будущее

Мы сейчас построим прогнозируемые временные ряды и параметры для:

  • NORTH: С корректировкой тренда

  • COAST: С корректировкой сезонности

  • EAST: Без изменений к оригиналу

North

m.plot(forecast[forecast["ID"] == "NORTH"])  # визуализация прогноза для региона NORTH
m.plot_parameters(df_name="NORTH")  # визуализация параметров модели для региона NORTH

South

m.plot(forecast[forecast["ID"] == "COAST"])  # визуализация прогноза для региона COAST
m.plot_parameters(df_name="COAST")  # визуализация параметров модели для региона COAST

East

m.plot(forecast[forecast["ID"] == "EAST"])  # визуализация прогноза для региона EAST
m.plot_parameters(df_name="EAST")  # визуализация параметров модели для региона EAST

Metrics

test_metrics_global = m.test(df_test)  # оценка модели на тестовых данных
test_metrics_global
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Runningstage.testing metric      DataLoader 0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        Loss_test           0.12341304123401642
         MAE_val            0.23543809354305267
        RMSE_val            0.26708388328552246
      RegLoss_test                  0.0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
MAE_val
RMSE_val
Loss_test
RegLoss_test

0

0.235438

0.267084

0.123413

0.0

Локальное моделирование тренда и сезонности

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

m = NeuralProphet(
    trend_global_local="local",  # локальный тренд
    season_global_local="local",  # локальная сезонность
    changepoints_range=0.8,  # доля периода, в котором могут находиться точки изменения
    epochs=20,  # количество эпох обучения
    trend_reg=5,  # параметр регуляризации для тренда
)
m.set_plotting_backend("plotly-static")  # выбор бэкэнда для построения графиков
metrics = m.fit(df_train, freq="H")  # обучение модели на обучающем наборе данных с частотой "H" (часы)
future = m.make_future_dataframe(df_test, n_historic_predictions=True)  # создание фрейма данных для будущих предсказаний на основе тестового набора данных с учетом исторических предсказаний
forecast = m.predict(future)  # предсказание на основе будущего фрейма данных

North

m.plot(forecast[forecast["ID"] == "NORTH"])  # построение графика прогноза для региона "NORTH"
m.plot_parameters(df_name="NORTH")  # визуализация параметров модели для региона "NORTH"

Coast

m.plot(forecast[forecast["ID"] == "COAST"])  # визуализация прогноза для региона "COAST"
m.plot_parameters(df_name="COAST")  # визуализация параметров модели для региона "COAST"

East

m.plot(forecast[forecast["ID"] == "EAST"])  # визуализация прогноза для региона "EAST"
m.plot_parameters(df_name="EAST")  # визуализация параметров модели для региона "EAST"

Metric

test_metrics_local = m.test(df_test)  # вычисление метрик качества модели на тестовом наборе данных
test_metrics_local  # вывод результатов
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Runningstage.testing metric      DataLoader 0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        Loss_test           0.08480319380760193
         MAE_val            0.18777026236057281
        RMSE_val             0.220332533121109
      RegLoss_test                  0.0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
MAE_val
RMSE_val
Loss_test
RegLoss_test

0

0.18777

0.220333

0.084803

0.0

Заключение

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

Last updated