Библиотека Greykite в Python: установка, настройка и практические примеры прогнозирования рядов

Greykite — библиотека для прогнозирования временных рядов с открытым исходным кодом, разработанная командой LinkedIn и выпущенная в 2021 году. Основу составляет алгоритм Silverkite — быстрая аддитивная модель, построенная на ridge-регрессии с богатым набором фич: тренд, сезонность, праздники, взаимодействия между компонентами.

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

Архитектура и ключевые компоненты

Greykite организована вокруг 3-х уровней абстракции:

  • Верхний уровень — класс Forecaster с методом run_forecast_config(), который принимает датафрейм и конфигурацию, возвращает объект с прогнозом, метриками и диагностикой;
  • Средний уровень — шаблоны (SimpleSilverkiteTemplate, SilverkiteTemplate, ProphetTemplate), которые транслируют конфигурацию в параметры модели;
  • Нижний уровень — FlexibleModel, непосредственно реализующий алгоритм Silverkite.

Ключевые компоненты конфигурации:

  • MetadataParam — описание данных: столбец даты, целевой столбец, частота временного ряда;
  • ModelComponentsParam — компоненты модели: тренд, сезонность, праздники, регуляризация, кастомные фичи;
  • EvaluationPeriodParam — параметры бэктестинга: размер тестовой выборки, количество фолдов, горизонт прогноза;
  • ForecastConfig — верхнеуровневый объект, объединяющий все параметры и передаваемый в Forecaster.

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

Silverkite vs PROPHET-модель внутри Greykite

Greykite поддерживает два алгоритма:

  • Silverkite (основной);
  • Prophet через обертку ProphetTemplate.

Выбор алгоритма задается параметром model в ForecastConfig.

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

Prophet использует байесовскую аддитивную модель на Stan — медленнее, но с неопределенностью прогноза из коробки. Использовать ProphetTemplate внутри Greykite имеет смысл, когда нужно сравнить алгоритмы в одном пайплайне с идентичными условиями бэктестинга — интерфейс и метрики унифицированы. Для продакшена Silverkite предпочтительнее: он быстрее, лучше поддается кастомизации и не требует компиляции Stan.

Установка и настройка Greykite

Библиотека Greykite распространяется через PyPI и устанавливается стандартным способом. Библиотека имеет нетривиальное дерево зависимостей: pandas, numpy, scikit-learn, plotly, LightGBM, pystan (опционально для Prophet). При установке в conda-окружении конфликты зависимостей минимальны; в базовом pip-окружении иногда требуется ручное разрешение версий.

Установка и зависимости

Базовая установка:

pip install greykite

Для работы с ProphetTemplate дополнительно:

pip install pystan==2.19.1.1
pip install prophet

Установка библиотек:

import greykite

from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, ModelComponentsParam, EvaluationPeriodParam
)

Совместимость: Python 3.7–3.10, pandas 1.x–2.x. При использовании pandas 2.0+ возможны предупреждения об устаревших методах внутри библиотеки — на функциональность не влияют. Но при этом важно настроить правильно окружение.

В случае если вы устанавливаете Greykite в Google Collab, то возможны ошибки из-за несовместимости версий Python и Pandas. Тогда подход к установке другой — тут либо нужно искать старые версии Kernel, либо откатиться на текущем к старым версиям сначала и создать обертку для Kernel и в нее потом оборачивать код в ячейках.

# Google Collab - Установка Python 3.10 и greykite
!apt-get update -y
!apt-get install -y python3.10 python3.10-distutils python3.10-dev
!curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10

!python3.10 -m pip install --upgrade pip
!python3.10 -m pip install numpy==1.26.0 pandas==1.5.3 holidays==0.13 holidays-ext==0.0.8 greykite
# Google Collab - Создание функции-обертки для последующих ячеек с кодом
import subprocess
import textwrap

def gk(code: str):
    """
    Выполняет Python код через Python 3.10 subprocess.
    Всё, что выводится в stdout, возвращается в текущую ячейку.
    """
    code = textwrap.dedent(code)
    result = subprocess.run(
        ["python3.10", "-c", code],
        capture_output=True,
        text=True
    )
    print(result.stdout)
    if result.stderr:
        print(result.stderr)
# Google Collab - Импорт библиотек через функцию-обертки gk (greykite на python 3.10)
gk("""import greykite

from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, ModelComponentsParam, EvaluationPeriodParam
)
print('All libraries are imported!')
""")
All libraries are imported!

В дальнейшем все ячейки кода, представленные ниже для Collab придется оборачивать в синтаксис gk(«»» … «»»). К счастью с локальной Conda таких «танцев с бубном» делать не приходится.

👉🏻  16 способов визуализации биржевых данных с помощью Matplotlib

Быстрый старт: минимальный рабочий пример

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

import pandas as pd
import numpy as np
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam
)

np.random.seed(42)
dates = pd.date_range(start="2022-01-01", periods=365, freq="D")
values = (
    10
    + 0.02 * np.arange(365)
    + 3 * np.sin(2 * np.pi * np.arange(365) / 7)
    + np.random.normal(0, 0.5, 365)
)
df = pd.DataFrame({"date": dates, "value": values})

config = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=30,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D"
    )
)

forecaster = Forecaster()
result = forecaster.run_forecast_config(df=df, config=config)

forecast_df = result.forecast.df
time_col = forecast_df.columns[0]

cols = [time_col, "forecast"]
if "forecast_lower" in forecast_df.columns:
    cols += ["forecast_lower", "forecast_upper"]

print(forecast_df[cols].tail(30))
Fitting 3 folds for each of 1 candidates, totalling 3 fits
            ts   forecast  forecast_lower  forecast_upper
365 2023-01-01  20.023034       18.738988       21.307079
366 2023-01-02  20.093147       18.570198       21.616096
367 2023-01-03  19.023206       17.546314       20.500097
368 2023-01-04  16.280607       15.177988       17.383225
369 2023-01-05  14.456036       13.426570       15.485502
370 2023-01-06  15.007097       13.795495       16.218698
371 2023-01-07  17.554038       16.703881       18.404194
372 2023-01-08  19.813449       18.865975       20.760924
373 2023-01-09  20.393763       19.283575       21.503950
374 2023-01-10  18.590435       17.505837       19.675033
375 2023-01-11  16.091606       14.993472       17.189739
376 2023-01-12  14.270478       13.236200       15.304755
377 2023-01-13  14.811891       13.583581       16.040201
378 2023-01-14  17.440300       16.579276       18.301324
379 2023-01-15  19.720877       18.757398       20.684356
380 2023-01-16  20.427656       19.301021       21.554292
381 2023-01-17  18.708125       17.619039       19.797211
382 2023-01-18  16.300514       15.201013       17.400014
383 2023-01-19  14.532079       13.506888       15.557269
384 2023-01-20  14.936239       13.361313       16.511164
385 2023-01-21  17.840243       16.735199       18.945286
386 2023-01-22  20.157648       18.920376       21.394919
387 2023-01-23  20.921299       19.462650       22.379948
388 2023-01-24  18.540246       17.094174       19.986317
389 2023-01-25  16.065397       14.627023       17.503772
390 2023-01-26  14.495541       13.175255       15.815826
391 2023-01-27  15.565867       14.332006       16.799729
392 2023-01-28  18.269831       17.406515       19.133147
393 2023-01-29  20.536058       19.582596       21.489520
394 2023-01-30  21.141656       20.024892       22.258421

Объект result содержит: forecast (датафрейм с прогнозом и доверительными интервалами), backtest (результаты backtesting), model (обученная модель). Этот минимальный пример уже включает автоматическое определение сезонности и тренда — Silverkite подбирает компоненты из пресета SILVERKITE по умолчанию.

Ключевые классы и методы

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

👉🏻  Методы аппроксимации временных рядов

Обзор классов и методов

Класс / метод Модуль Назначение Ключевые параметры
Forecaster framework.templates.forecaster Верхнеуровневый запуск пайплайна
run_forecast_config() Forecaster Запуск прогноза по конфигурации df, config
ForecastConfig framework.templates.autogen.forecast_config Верхнеуровневая конфигурация model_template, forecast_horizon, metadata_param, model_components_param, evaluation_period_param
MetadataParam framework.templates.autogen.forecast_config Описание структуры датафрейма time_col, value_col, freq, train_end_date
ModelComponentsParam framework.templates.autogen.forecast_config Настройка компонент модели seasonality, growth, events, regressors, custom
EvaluationPeriodParam framework.templates.autogen.forecast_config Параметры бэктестинга test_horizon, periods_between_train_test, cv_max_splits, cv_min_train_periods
SimpleSilverkiteTemplate framework.templates.simple_silverkite_template Упрощенный шаблон с пресетами SimpleSilverkiteTemplateOptions
SilverkiteTemplate framework.templates.silverkite_template Полный контроль над Silverkite ModelComponentsParam (расширенный)
FlexibleModel sklearn.estimator.silverkite_estimator sklearn-совместимый estimator fit_algorithm, feature_sets_enabled, extra_pred_cols
SilverkiteEstimator sklearn.estimator.silverkite_estimator Обертка Silverkite для sklearn API time_properties, origin_for_time_vars, fs_components_df
ProphetTemplate framework.templates.prophet_template Обертка Prophet в пайплайне Greykite ModelComponentsParam (Prophet-параметры)

Forecaster и SimpleSilverkiteTemplate

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

Метод SimpleSilverkiteTemplate работает через пресеты SimpleSilverkiteTemplateOptions, которые задают частоту данных и уровень детализации модели:

from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam
)
from greykite.framework.templates.simple_silverkite_template_config import (
    SILVERKITE_DAILY_90
)

config = ForecastConfig(
    model_template=SILVERKITE_DAILY_90,
    forecast_horizon=30,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D"
    )
)

Доступные пресеты охватывают комбинации частот (hourly, daily, weekly) и горизонтов. SILVERKITE_DAILY_90 оптимален для дневных бизнес-метрик с горизонтом до квартала: включает дневную и недельную сезонность, праздники США, линейный тренд с changepoints.

FlexibleModel и кастомизация компонент

FlexibleModel — sklearn-совместимый estimator, дающий прямой доступ к механизму генерации фич Silverkite. Используется, когда пайплайн Forecaster избыточен: например, при интеграции в собственный sklearn Pipeline или при необходимости передать модель в GridSearchCV.

from greykite.sklearn.estimator.silverkite_estimator import SilverkiteEstimator
import pandas as pd

fs_components_df = pd.DataFrame({
    "name": ["tow", "toy"],
    "period": [7.0, 365.25],
    "order": [3, 5],
    "seas_names": ["weekly", "yearly"]
})

estimator = SilverkiteEstimator(
    fit_algorithm_dict={
        "fit_algorithm": "ridge",
        "fit_algorithm_params": {"alpha": 0.1}
    },
    fs_components_df=fs_components_df,
    extra_pred_cols=["ct1"]
)

print(estimator.fit_algorithm_dict)
print(estimator.extra_pred_cols)
print(estimator.fs_components_df)
{'fit_algorithm': 'ridge', 'fit_algorithm_params': {'alpha': 0.1}}
['ct1']
  name  period  order seas_names
0  tow    7.00      3     weekly
1  toy  365.25      5     yearly

fs_components_df — ключевой параметр: задает компоненты Фурье-разложения для каждой сезонности. Столбец order контролирует количество гармоник: выше значение — сложнее форма сезонности, выше риск переобучения. Для большинства бизнес-метрик order=3–5 достаточно.

Параметры сезонности и их влияние

Сезонность в Silverkite моделируется через Фурье-разложение. Каждый сезонный компонент описывается тремя параметрами:

  • period — период сезонности в единицах временного ряда (7.0 для недельной сезонности дневного ряда);
  • order — количество пар sin/cos гармоник; определяет сложность формы сезонного паттерна;
  • seas_names — имя компонента для интерпретации и диагностики.

Через ModelComponentsParam сезонность задается так:

model_components = ModelComponentsParam(
    seasonality={
        "fs_components_df": pd.DataFrame({
            "name": ["tow", "toy"],
            "period": [7.0, 365.25],
            "order": [3, 5],
            "seas_names": ["weekly", "yearly"]
        })
    }
)

Увеличение order с 3 до 8 для годовой сезонности улучшает качество на данных с нерегулярными пиками (например, e-commerce с несколькими пиковыми сезонами), но при коротких рядах (менее 2 полных циклов) приводит к переобучению. Практическое правило: order ≤ period/2, при этом для дневных данных weekly order=3–4, yearly order=5–8.

Обработка праздников и событий: Holiday и EventConfig

Библиотека Greykite содержит встроенные словари праздников для десятков стран через модуль greykite.common.features.holiday. Праздники добавляются как бинарные фичи с опциональным окном до и после события — это позволяет захватить эффект предпраздничного и послепраздничного поведения.

from greykite.framework.templates.autogen.forecast_config import ModelComponentsParam
from greykite.algo.forecast.silverkite.constants.silverkite_holiday import SilverkiteHoliday

model_components = ModelComponentsParam(
    events={
        "holidays_to_model_separately": SilverkiteHoliday.ALL_HOLIDAYS_IN_COUNTRIES,
        "holiday_lookup_countries": ["US", "RU"],
        "holiday_pre_num_days": 2,
        "holiday_post_num_days": 2,
        "holiday_pre_post_num_dict": {
            "Christmas Day": {"pre_num": 5, "post_num": 3}
        }
    }
)

print(model_components.events)
{'holidays_to_model_separately': 'ALL_HOLIDAYS_IN_COUNTRIES', 'holiday_lookup_countries': ['US', 'RU'], 'holiday_pre_num_days': 2, 'holiday_post_num_days': 2, 'holiday_pre_post_num_dict': {'Christmas Day': {'pre_num': 5, 'post_num': 3}}}

Метод holiday_pre_post_num_dict позволяет задать индивидуальные окна для конкретных праздников. Это важно для метрик с асимметричным эффектом: например, трафик начинает падать за 5 дней до Нового года, но восстанавливается быстро. Кастомные события (акции, релизы продуктов) добавляются аналогично через параметр daily_event_df_dict.

👉🏻  Собственные числа и собственные векторы в финансах: разложения PCA и SVD

Параметры регуляризации и переобучение

Silverkite использует ridge-регрессию как базовый fit-алгоритм, что обеспечивает встроенную L2-регуляризацию. Параметр alpha в fit_algorithm_params контролирует силу регуляризации: при alpha=0 модель вырождается в OLS, при высоких значениях — сглаживает коэффициенты к нулю.

from greykite.framework.templates.autogen.forecast_config import ModelComponentsParam

model_components = ModelComponentsParam(
    custom={
        "fit_algorithm_dict": {
            "fit_algorithm": "ridge",
            "fit_algorithm_params": {"alpha": 1.0}
        },
        "feature_sets_enabled": True,
        "max_lag_order": 7
    }
)

print(model_components.custom)
{'fit_algorithm_dict': {'fit_algorithm': 'ridge', 'fit_algorithm_params': {'alpha': 1.0}}, 'feature_sets_enabled': True, 'max_lag_order': 7}

Помимо ridge, доступны:

  • lasso (L1, автоматический отбор фич),
  • elastic_net (комбинация L1+L2),
  • gradient_boosting (LightGBM).

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

Практические примеры

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

Базовый пайплайн прогнозирования

Полный рабочий пайплайн с явной конфигурацией всех основных компонентов:

import pandas as pd
import numpy as np
import yfinance as yf
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, ModelComponentsParam, EvaluationPeriodParam
)

raw = yf.download("GC=F", start="2024-03-15", end="2026-03-15", auto_adjust=False)
if isinstance(raw.columns, pd.MultiIndex):
    raw.columns = raw.columns.droplevel(1)
df = raw[["Close"]].reset_index()
df.columns = ["date", "value"]
df = df.dropna()

config = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=60,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="B"
    ),
    model_components_param=ModelComponentsParam(
        seasonality={
            "weekly_seasonality": True,
            "yearly_seasonality": True,
            "daily_seasonality": False
        },
        growth={"growth_term": "linear"},
        custom={
            "fit_algorithm_dict": {
                "fit_algorithm": "ridge",
                "fit_algorithm_params": {"alphas": [0.1, 0.5, 1.0, 5.0]}
            }
        }
    ),
    evaluation_period_param=EvaluationPeriodParam(
        test_horizon=60,
        cv_max_splits=3
    )
)

forecaster = Forecaster()
result = forecaster.run_forecast_config(df=df, config=config)

forecast_df = result.forecast.df
time_col = forecast_df.columns[0]
cols = [time_col, "forecast"]
if "forecast_lower" in forecast_df.columns:
    cols += ["forecast_lower", "forecast_upper"]

print(forecast_df[cols].tail(10))
print()

metrics = result.backtest.test_evaluation

metrics_df = pd.DataFrame.from_dict(metrics, orient="index", columns=["value"])
metrics_df.index.name = "metric"
metrics_df = metrics_df.dropna()
metrics_df["value"] = metrics_df["value"].round(4)

print(metrics_df.to_string())
Fitting 3 folds for each of 1 candidates, totalling 3 fits
            ts     forecast  forecast_lower  forecast_upper
571 2026-05-25  5639.802733     5428.397697     5851.207770
572 2026-05-26  5801.730005     5639.637975     5963.822034
573 2026-05-27  5769.728471     5588.202641     5951.254301
574 2026-05-28  5779.971361     5604.573362     5955.369361
575 2026-05-29  5719.376305     5556.220341     5882.532269
576 2026-06-01  5652.507480     5446.601979     5858.412981
577 2026-06-02  5808.266952     5650.315223     5966.218680
578 2026-06-03  5805.647844     5627.454178     5983.841511
579 2026-06-04  5805.060198     5630.116390     5980.004007
580 2026-06-05  5752.017052     5589.280764     5914.753341

                                                         value
metric                                                        
CORR                                                    0.8597
R2                                                      0.1949
MSE                                                 72088.2887
RMSE                                                  268.4926
MAE                                                   220.8951
MedAE                                                 202.4796
MAPE                                                    4.4383
MedAPE                                                  4.1831
sMAPE                                                   2.2921
Q80                                                   176.2381
Q95                                                   209.1333
Q99                                                   217.9054
OutsideTolerance1p                                      0.9286
OutsideTolerance2p                                      0.8393
OutsideTolerance3p                                      0.6429
OutsideTolerance4p                                      0.5536
OutsideTolerance5p                                      0.3214
Prediction Band Width (%)                               5.1945
Prediction Band Coverage (fraction)                     0.3393
Coverage: Lower Band                                    0.0357
Coverage: Upper Band                                    0.3036
Coverage Diff: Actual_Coverage - Intended_Coverage     -0.6107
MIS                                                  4684.3228

Пайплайн загружает котировки фьючерса на золото, формирует конфигурацию с недельной и годовой сезонностью в единицах бизнес-дней, запускает прогноз на 60 дней вперед с 3-фолдовым бэктестингом. Переменная result.backtest.test_evaluation содержит метрики по каждому фолду: MAPE, RMSE, покрытие доверительного интервала.

👉🏻  Применение NumPy для финансового анализа

Интерпретация полученных данных кратко следующая:

  1. Модель показывает умеренное качество точечного прогноза: MAPE=4.4% и CORR=0.86 говорят о том, что направление движения цены модель улавливает, но R²=0.19 указывает на слабое объяснение дисперсии — фактически модель лишь немного лучше наивного прогноза средним. RMSE=268 при ценах золота в районе 5600–5800 — это ошибка около 4.7% от уровня;
  2. Главная проблема — доверительные интервалы. Coverage=0.34 при заданном 0.95 означает, что реальные значения попадают в интервал лишь в 34% случаев вместо 95%. Это типичная картина для финансовых рядов с гетероскедастичностью: Silverkite строит интервалы на основе остатков обучающей выборки, не учитывая кластеризацию волатильности. Для золота на горизонте 60 дней узкий интервал (Band Width=5.2%) — заведомо оптимистичная оценка неопределенности, использовать его для риск-менеджмента не стоит.

Учет праздников и аномалий

Аномалии (выбросы, периоды с аномальным поведением ряда) снижают качество обучения, если не исключить их явно. Greykite поддерживает маскировку аномальных периодов через AnomalyParam:

import pandas as pd
import numpy as np
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, ModelComponentsParam
)

forecaster = Forecaster()

np.random.seed(0)
dates = pd.date_range("2021-01-01", periods=730, freq="D")
values = 100 + np.sin(2 * np.pi * np.arange(730) / 365) * 10 + np.random.normal(0, 2, 730)
values[180:210] += 50
df_anom = pd.DataFrame({"date": dates, "value": values})

anomaly_df = pd.DataFrame({
    "start_time": ["2021-07-01"],
    "end_time": ["2021-07-31"],
    "impact": [None]
})

config_anom = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=30,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D",
        anomaly_info={
            "value_col": "value",
            "anomaly_df": anomaly_df,
            "adjustment_delta_col": None
        }
    ),
    model_components_param=ModelComponentsParam(
        events={
            "holiday_lookup_countries": ["US"],
            "holiday_pre_num_days": 1,
            "holiday_post_num_days": 1
        }
    )
)

result_anom = forecaster.run_forecast_config(df=df_anom, config=config_anom)

forecast_df_anom = result_anom.forecast.df
time_col = forecast_df_anom.columns[0]
cols = [time_col, "forecast"]
if "forecast_lower" in forecast_df_anom.columns:
    cols += ["forecast_lower", "forecast_upper"]

print(forecast_df_anom[cols].tail(10))
Fitting 3 folds for each of 1 candidates, totalling 3 fits
            ts   forecast  forecast_lower  forecast_upper
750 2023-01-21  98.314588       87.635350      108.993826
751 2023-01-22  98.807028       89.044297      108.569758
752 2023-01-23  99.209329       88.731770      109.686888
753 2023-01-24  99.529496       89.689293      109.369699
754 2023-01-25  99.622384       86.923972      112.320796
755 2023-01-26  99.097517       87.111011      111.084023
756 2023-01-27  99.035790       88.191912      109.879668
757 2023-01-28  99.033954       88.345302      109.722606
758 2023-01-29  99.434466       89.661600      109.207331
759 2023-01-30  99.663221       89.180127      110.146315

AnomalyParam принимает датафрейм с периодами аномалий. При impact=None период полностью исключается из обучающей выборки — модель не видит искаженные данные. Альтернативно, impact можно задать как числовой сдвиг для корректировки значений без исключения.

Кастомизация компонент через ModelComponentsParam

Добавление внешних регрессоров расширяет модель за пределы временных паттернов. Регрессоры передаются как дополнительные столбцы датафрейма:

import pandas as pd
import numpy as np
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, ModelComponentsParam
)

forecaster = Forecaster()

np.random.seed(42)
dates = pd.date_range(start="2022-01-01", periods=365, freq="D")
values = (
    10
    + 0.02 * np.arange(365)
    + 3 * np.sin(2 * np.pi * np.arange(365) / 7)
    + np.random.normal(0, 0.5, 365)
)
df = pd.DataFrame({"date": dates, "value": values})

df_reg = df.copy()
df_reg["lag_7"] = df_reg["value"].shift(7)
df_reg["lag_30"] = df_reg["value"].shift(30)
df_reg = df_reg.dropna()

config_reg = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=30,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D"
    ),
    model_components_param=ModelComponentsParam(
        regressors={
            "regressor_cols": ["lag_7", "lag_30"]
        },
        custom={
            "fit_algorithm_dict": {
                "fit_algorithm": "lasso",
                "fit_algorithm_params": {"alphas": [0.01, 0.1, 1.0]}
            }
        }
    )
)

result_reg = forecaster.run_forecast_config(df=df_reg, config=config_reg)

forecast_df_reg = result_reg.forecast.df
time_col = forecast_df_reg.columns[0]
cols = [time_col, "forecast"]
if "forecast_lower" in forecast_df_reg.columns:
    cols += ["forecast_lower", "forecast_upper"]

print(forecast_df_reg[cols].tail(10))
Fitting 3 folds for each of 1 candidates, totalling 3 fits

Lasso здесь предпочтителен: при большом количестве лаговых регрессоров он обнуляет незначимые коэффициенты, автоматически отбирая информативные лаги. extra_pred_cols поддерживает синтаксис взаимодействий через двоеточие — это позволяет задавать условные эффекты без ручного создания фич.

👉🏻  Сглаживание временных рядов и шума в данных с помощью Kalman Filter

Бэктестинг и валидация на rolling window

Метод EvaluationPeriodParam контролирует схему бэктестинга. В библиотеке Greykite реализовано расширяющееся окно (expanding window) по умолчанию, хотя через параметры можно приблизиться к rolling window:

import pandas as pd
import numpy as np
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam, EvaluationPeriodParam
)

forecaster = Forecaster()

np.random.seed(42)
dates = pd.date_range(start="2022-01-01", periods=365, freq="D")
values = (
    10
    + 0.02 * np.arange(365)
    + 3 * np.sin(2 * np.pi * np.arange(365) / 7)
    + np.random.normal(0, 0.5, 365)
)
df = pd.DataFrame({"date": dates, "value": values})

config_bt = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=30,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D"
    ),
    evaluation_period_param=EvaluationPeriodParam(
        test_horizon=30,
        periods_between_train_test=0,
        cv_max_splits=5,
        cv_min_train_periods=180,
        cv_expanding_window=True,
        cv_horizon=30
    )
)

result_bt = forecaster.run_forecast_config(df=df, config=config_bt)

cv_results = result_bt.grid_search.cv_results_
cv_df = pd.DataFrame(cv_results)
metric_cols = [c for c in cv_df.columns if "MAPE" in c or "RMSE" in c]
print(cv_df[metric_cols])
Fitting 5 folds for each of 1 candidates, totalling 5 fits
   split0_test_RMSE  split1_test_RMSE  ...  mean_train_sMAPE  std_train_sMAPE
0          0.638277          0.674613  ...           1.37745         0.049042

[1 rows x 45 columns]

cv_expanding_window=False переключает на rolling window с фиксированным размером обучающей выборки — актуально для рядов с концептуальным дрейфом, где ранние данные снижают качество. cv_min_train_periods защищает от фолдов с недостаточным объемом данных для обучения.

Визуализация прогноза и компонент модели

Greykite предоставляет встроенные plotly-визуализации через объект result:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.templates.autogen.forecast_config import (
    ForecastConfig, MetadataParam
)

np.random.seed(42)
dates = pd.date_range(start="2022-01-01", periods=365, freq="D")
values = (
    10
    + 0.02 * np.arange(365)
    + 3 * np.sin(2 * np.pi * np.arange(365) / 7)
    + np.random.normal(0, 0.5, 365)
)
df = pd.DataFrame({"date": dates, "value": values})

config = ForecastConfig(
    model_template=ModelTemplateEnum.SILVERKITE.name,
    forecast_horizon=30,
    coverage=0.95,
    metadata_param=MetadataParam(
        time_col="date",
        value_col="value",
        freq="D"
    )
)

forecaster = Forecaster()
result = forecaster.run_forecast_config(df=df, config=config)

forecast_df = result.forecast.df.copy()
time_col = forecast_df.columns[0]
forecast_df[time_col] = pd.to_datetime(forecast_df[time_col])
train_end = df["date"].max()

hist = forecast_df[forecast_df[time_col] <= train_end] 
pred = forecast_df[forecast_df[time_col] > train_end]

fig, axes = plt.subplots(2, 1, figsize=(14, 8), facecolor="white")

ax1 = axes[0]
ax1.plot(hist[time_col], hist["actual"], color="#1a1a1a", linewidth=1.2, label="Факт")
ax1.plot(pred[time_col], pred["forecast"], color="#2563eb", linewidth=1.5,
         linestyle="--", label="Прогноз")
if "forecast_lower" in pred.columns:
    ax1.fill_between(pred[time_col], pred["forecast_lower"], pred["forecast_upper"],
                     alpha=0.15, color="#2563eb", label="95% интервал")
ax1.axvline(train_end, color="#6b7280", linewidth=1, linestyle=":")
ax1.set_title("Прогноз Greykite (Silverkite)", fontsize=13, pad=10)
ax1.legend(fontsize=10)
ax1.grid(True, alpha=0.3)
ax1.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m"))

ax2 = axes[1]
bt_dict = result.backtest.test_evaluation
if bt_dict is not None:
    bt_series = pd.Series(bt_dict)
    metrics = ["MAPE", "RMSE"]
    metrics = [m for m in metrics if m in bt_series.index]
    ax2.bar(range(len(metrics)),
            [bt_series[m] for m in metrics],
            color=["#1a1a1a", "#6b7280"])
    ax2.set_xticks(range(len(metrics)))
    ax2.set_xticklabels(metrics)
    ax2.set_title("Метрики backtesting", fontsize=13, pad=10)
    ax2.grid(True, alpha=0.3, axis="y")

plt.tight_layout()
plt.savefig("greykite_forecast.png", dpi=150, bbox_inches="tight")
plt.show()

Прогноз Greykite на дневных данных. Верхняя панель: исторический ряд (черный) и прогноз на 60 дней вперед (синий пунктир) с 95% доверительным интервалом. Вертикальная пунктирная линия — граница обучающей и тестовой выборки. Нижняя панель: агрегированные метрики бэктестинга. Ширина интервала прогноза — индикатор неопределенности модели; резкое расширение на горизонте более 30 дней сигнализирует о слабой предсказуемости ряда

Рис. 1: Прогноз Greykite на дневных данных. Верхняя панель: исторический ряд (черный) и прогноз на 60 дней вперед (синий пунктир) с 95% доверительным интервалом. Вертикальная пунктирная линия — граница обучающей и тестовой выборки. Нижняя панель: агрегированные метрики бэктестинга. Ширина интервала прогноза — индикатор неопределенности модели; резкое расширение на горизонте более 30 дней сигнализирует о слабой предсказуемости ряда

Работа с библиотекой: частые ошибки и лучшие практики

Большинство проблем при работе с Greykite возникает на этапе конфигурации и подготовки данных. Ошибки конфигурации чаще всего проявляются не как исключения Python, а как деградация качества прогноза — их сложнее отловить без диагностики.

👉🏻  Продвинутые методы предиктивной аналитики с глубокими нейронными сетями

Типичные ошибки

  1. Неверная частота ряда. Параметр freq в MetadataParam должен точно соответствовать фактической частоте данных. Пропуски в ряду (выходные для дневных данных) требуют freq=»B» вместо «D». При несоответствии Silverkite генерирует фичи с неверными периодами сезонности, что незаметно деградирует качество;
  2. Утечка данных через регрессоры. При добавлении внешних регрессоров они должны быть доступны на горизонте прогноза. Лаговые регрессоры (lag_7, lag_30) безопасны только если lag ≥ forecast_horizon. Регрессоры с lag < forecast_horizon создают риск утечки данных из будущего (look-ahead bias): в результате на бэктестах метрики выглядят хорошо, а в продакшене модель показывает себя из рук вон плохо;
  3. Переобучение при высоком порядке (order) сезонности. order=10+ для годовой сезонности на ряду менее 2 лет гарантированно приводит к переобучению. Симптом: низкий RMSE на train, высокий на test в backtesting. Решение: cv_max_splits≥3 и контроль разницы train/test метрик;
  4. Игнорирование линий сломов (changepoints) тренда. По умолчанию Silverkite использует линейный тренд без изломов. Для рядов со структурными сдвигами (кризисы, редизайн продукта) нужно явно задать changepoints. Если нет желания заморачиваться, то method=»auto» автоматически определяет точки излома через регуляризованную регрессию. regularization_strength контролирует чувствительность: 0.0 — максимум точек, 1.0 — минимум.

Лучшие практики

  1. Всегда запускать backtesting с cv_max_splits≥3 перед деплойментом в продакшен, поскольку одиночный train/test сплит дает нестабильные оценки качества;
  2. Для бизнес-метрик с выраженной недельной сезонностью использовать freq=»D» с tow-компонентой, а не агрегировать до недельных данных — теряется информация о внутринедельных паттернах;
  3. При добавлении праздников для нескольких стран проверять пересечения дат: совпадающие праздники создают дублирующие фичи и раздувают матрицу регрессии;
  4. Использовать result.model[-1].named_steps[«estimator»].model_dict для доступа к коэффициентам модели — это основной инструмент диагностики того, какие компоненты реально влияют на прогноз;
  5. Для рядов с мультипликативной сезонностью (амплитуда сезонности растет с уровнем ряда) логарифмировать таргет перед подачей в модель — Silverkite аддитивен по природе.

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

Заключение

Библиотека Greykite несомненно интересна. Она, по сути, закрывает нишу между «слишком простым» и «слишком сложным»: Prophet не дает достаточного контроля над структурой модели, а нейросетевые подходы требуют больших данных и теряют интерпретируемость.

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

Практическая ценность библиотеки раскрывается в понятности ее поведения в продакшене и, разумеется, универсальности: есть встроенный модуль бэктестинга, есть детектирование аномалий, есть гибкая настройка changepoints и поддержка внешних регрессоров. Все они формируют полный аналитический пайплайн без необходимости собирать его из разрозненных инструментов. Для задач прогнозирования бизнес-метрик с выраженной сезонностью и внешними событиями Greykite — один из наиболее зрелых инструментов в экосистеме Python.