Prophet – прогнозирование временных рядов от Facebook

онлайн тренажер по питону
Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Prophet – прогнозирование временных рядов от Facebook: полное руководство по анализу данных

Введение в Prophet

Prophet — это мощная библиотека с открытым исходным кодом, разработанная командой Facebook (Meta) для прогнозирования временных рядов. Библиотека была создана для решения практических задач прогнозирования в условиях реального бизнеса, где данные могут содержать пропуски, выбросы и сложные сезонные паттерны.

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

История создания и развития библиотеки

Prophet был впервые представлен в 2017 году исследователями из Facebook Core Data Science Team. Библиотека создавалась для решения конкретных задач компании по прогнозированию различных метрик: от активности пользователей до планирования инфраструктуры.

Основными разработчиками выступили Sean Taylor и Ben Letham, которые стремились создать инструмент, сочетающий в себе статистическую строгость и практическую применимость. В 2018 году была выпущена версия для R, а позже библиотека была портирована на Python.

Математические основы и принципы работы

Аддитивная модель Prophet

Моделирование тренда

Prophet поддерживает два типа трендов:

Линейный тренд: [ g(t) = (k + a(t)^T \delta) \cdot t + (m + a(t)^T \gamma) ]

Логистический тренд: [ g(t) = \frac{C(t)}{1 + \exp(-(k + a(t)^T \delta)(t - (m + a(t)^T \gamma)))} ]

где [ C(t) ] — carrying capacity (максимальная емкость), [ k ] — базовая скорость роста, [ \delta ] — изменения скорости роста в точках изменения тренда.

Сезонная составляющая

Сезонность моделируется с помощью рядов Фурье:

где [ P ] — период сезонности, [ N ] — количество гармоник (fourier_order).

Установка и настройка среды

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

pip install prophet

Установка с дополнительными зависимостями

pip install prophet[plot]
pip install plotly  # для интерактивной визуализации

Установка для различных операционных систем

Windows:

pip install pystan
pip install prophet

macOS:

brew install gcc
pip install prophet

Linux (Ubuntu/Debian):

sudo apt-get install build-essential
pip install prophet

Подключение библиотеки

from prophet import Prophet
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from prophet.plot import plot_plotly, plot_components_plotly

Подготовка данных для модели

Требования к формату данных

Prophet строго требует следующую структуру данных:

  1. Столбец 'ds' — временные метки (datetime)
  2. Столбец 'y' — значения временного ряда (numeric)

Пример подготовки данных

import pandas as pd
from datetime import datetime, timedelta

# Создание примера данных
dates = pd.date_range(start='2020-01-01', end='2023-12-31', freq='D')
values = np.random.randn(len(dates)).cumsum() + 100

df = pd.DataFrame({
    'ds': dates,
    'y': values
})

# Обработка реальных данных
df = pd.read_csv('your_data.csv')
df['ds'] = pd.to_datetime(df['date_column'])
df['y'] = pd.to_numeric(df['value_column'], errors='coerce')

# Удаление пропущенных значений
df = df.dropna(subset=['ds', 'y'])
df = df.sort_values('ds').reset_index(drop=True)

Валидация данных

def validate_prophet_data(df):
    """Проверка данных для Prophet"""
    assert 'ds' in df.columns, "Отсутствует столбец 'ds'"
    assert 'y' in df.columns, "Отсутствует столбец 'y'"
    assert df['ds'].dtype == 'datetime64[ns]', "Столбец 'ds' должен быть datetime"
    assert pd.api.types.is_numeric_dtype(df['y']), "Столбец 'y' должен быть числовым"
    assert df['ds'].is_monotonic_increasing, "Даты должны быть отсортированы"
    
    print(f"Данные корректны. Период: {df['ds'].min()} - {df['ds'].max()}")
    print(f"Количество наблюдений: {len(df)}")
    print(f"Пропущенных значений: {df['y'].isna().sum()}")

Базовое обучение модели и построение прогнозов

Создание и обучение модели

# Инициализация модели
model = Prophet()

# Обучение модели
model.fit(df)

# Создание будущего датафрейма
future = model.make_future_dataframe(periods=365)  # прогноз на год

# Построение прогноза
forecast = model.predict(future)

Анализ результатов прогноза

# Просмотр основных колонок прогноза
forecast_columns = ['ds', 'yhat', 'yhat_lower', 'yhat_upper', 'trend', 'seasonal']
print(forecast[forecast_columns].tail(10))

# Статистика прогноза
print(f"Средний прогноз: {forecast['yhat'].mean():.2f}")
print(f"Доверительный интервал: [{forecast['yhat_lower'].mean():.2f}, {forecast['yhat_upper'].mean():.2f}]")

Визуализация результатов

Статическая визуализация

import matplotlib.pyplot as plt

# Основной график прогноза
fig1 = model.plot(forecast)
plt.title('Прогноз временного ряда')
plt.xlabel('Дата')
plt.ylabel('Значение')
plt.show()

# Компонентный анализ
fig2 = model.plot_components(forecast)
plt.show()

Интерактивная визуализация

from prophet.plot import plot_plotly, plot_components_plotly

# Интерактивный график прогноза
fig = plot_plotly(model, forecast)
fig.show()

# Интерактивный компонентный анализ
fig_components = plot_components_plotly(model, forecast)
fig_components.show()

Кастомная визуализация

def plot_forecast_custom(model, forecast, df):
    """Кастомная визуализация прогноза"""
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10))
    
    # Основной прогноз
    ax1.plot(df['ds'], df['y'], 'ko', markersize=3, label='Исторические данные')
    ax1.plot(forecast['ds'], forecast['yhat'], 'b-', label='Прогноз')
    ax1.fill_between(forecast['ds'], forecast['yhat_lower'], forecast['yhat_upper'], 
                     alpha=0.3, color='blue', label='Доверительный интервал')
    ax1.set_title('Прогноз временного ряда')
    ax1.legend()
    ax1.grid(True)
    
    # Остатки
    historical_forecast = forecast[forecast['ds'].isin(df['ds'])]
    residuals = df['y'].values - historical_forecast['yhat'].values
    ax2.plot(df['ds'], residuals, 'ro', markersize=2)
    ax2.axhline(y=0, color='k', linestyle='--')
    ax2.set_title('Остатки модели')
    ax2.grid(True)
    
    plt.tight_layout()
    plt.show()

Компонентный анализ временного ряда

Анализ тренда

# Извлечение тренда
trend = forecast['trend']
print(f"Начальное значение тренда: {trend.iloc[0]:.2f}")
print(f"Конечное значение тренда: {trend.iloc[-1]:.2f}")
print(f"Общий рост: {trend.iloc[-1] - trend.iloc[0]:.2f}")

# Скорость роста
growth_rate = (trend.iloc[-1] - trend.iloc[0]) / len(trend)
print(f"Средняя скорость роста: {growth_rate:.4f} единиц в день")

Анализ сезонности

# Извлечение сезонных компонентов
weekly_seasonality = forecast.filter(regex='weekly').mean()
yearly_seasonality = forecast.filter(regex='yearly').mean()

print("Сезонные эффекты:")
print(f"Недельная сезонность: {weekly_seasonality.abs().mean():.2f}")
print(f"Годовая сезонность: {yearly_seasonality.abs().mean():.2f}")

Настройка параметров модели

Основные параметры

model = Prophet(
    # Сезонность
    daily_seasonality=True,          # Дневная сезонность
    weekly_seasonality=True,         # Недельная сезонность
    yearly_seasonality=True,         # Годовая сезонность
    
    # Режим сезонности
    seasonality_mode='additive',     # 'additive' или 'multiplicative'
    
    # Чувствительность к изменениям
    changepoint_prior_scale=0.05,    # Чувствительность к изменениям тренда
    seasonality_prior_scale=10.0,    # Регуляризация сезонности
    holidays_prior_scale=10.0,       # Регуляризация праздников
    
    # Доверительный интервал
    interval_width=0.95,             # Ширина доверительного интервала
    
    # Количество точек изменения тренда
    n_changepoints=25,               # Количество потенциальных точек изменения
    
    # Диапазон точек изменения
    changepoint_range=0.8            # Доля данных для поиска изменений
)

Оптимизация параметров

from sklearn.metrics import mean_absolute_error, mean_squared_error

def optimize_prophet_parameters(df, param_grid):
    """Оптимизация параметров Prophet"""
    best_mae = float('inf')
    best_params = None
    
    # Разделение на обучающую и тестовую выборки
    train_size = int(len(df) * 0.8)
    train_df = df[:train_size]
    test_df = df[train_size:]
    
    for params in param_grid:
        model = Prophet(**params)
        model.fit(train_df)
        
        # Прогноз на тестовой выборке
        future = model.make_future_dataframe(periods=len(test_df))
        forecast = model.predict(future)
        
        # Вычисление MAE
        test_forecast = forecast.tail(len(test_df))
        mae = mean_absolute_error(test_df['y'], test_forecast['yhat'])
        
        if mae < best_mae:
            best_mae = mae
            best_params = params
    
    return best_params, best_mae

# Пример сетки параметров
param_grid = [
    {'changepoint_prior_scale': 0.01, 'seasonality_prior_scale': 0.1},
    {'changepoint_prior_scale': 0.05, 'seasonality_prior_scale': 1.0},
    {'changepoint_prior_scale': 0.1, 'seasonality_prior_scale': 10.0},
]

Работа с праздниками и особыми событиями

Создание календаря праздников

# Определение праздников
holidays = pd.DataFrame({
    'holiday': ['Новый год', 'Рождество', 'День защитника Отечества', 
                'Международный женский день', 'Праздник Весны и Труда'],
    'ds': pd.to_datetime(['2023-01-01', '2023-01-07', '2023-02-23', 
                         '2023-03-08', '2023-05-01']),
    'lower_window': [-1, -1, 0, 0, 0],      # Дни до праздника
    'upper_window': [1, 1, 0, 0, 0],        # Дни после праздника
})

# Использование встроенных праздников
model = Prophet()
model.add_country_holidays(country_name='RU')  # Российские праздники
model.fit(df)

Кастомные события

# Создание событий для промо-акций
promo_events = pd.DataFrame({
    'holiday': 'promo_campaign',
    'ds': pd.to_datetime(['2023-03-15', '2023-06-15', '2023-09-15', '2023-12-15']),
    'lower_window': 0,
    'upper_window': 7,  # Эффект длится неделю
})

# Объединение с основными праздниками
all_holidays = pd.concat([holidays, promo_events], ignore_index=True)

model = Prophet(holidays=all_holidays)
model.fit(df)

Добавление внешних регрессоров

Простой регрессор

# Добавление температуры как регрессора
df['temperature'] = np.random.normal(20, 10, len(df))

model = Prophet()
model.add_regressor('temperature')
model.fit(df)

# Для прогноза нужны будущие значения регрессора
future = model.make_future_dataframe(periods=30)
future['temperature'] = np.random.normal(20, 10, len(future))
forecast = model.predict(future)

Множественные регрессоры

# Добавление нескольких регрессоров
df['marketing_spend'] = np.random.exponential(1000, len(df))
df['competitor_price'] = np.random.normal(100, 20, len(df))

model = Prophet()
model.add_regressor('temperature')
model.add_regressor('marketing_spend')
model.add_regressor('competitor_price', standardize=True)

model.fit(df)

Пользовательские сезонности

Добавление кастомной сезонности

# Месячная сезонность
model = Prophet()
model.add_seasonality(name='monthly', period=30.5, fourier_order=5)

# Квартальная сезонность
model.add_seasonality(name='quarterly', period=91.25, fourier_order=8)

# Условная сезонность (только для определенных условий)
def is_weekend(ds):
    date = pd.to_datetime(ds)
    return date.weekday() >= 5

df['is_weekend'] = df['ds'].apply(is_weekend)
model.add_seasonality(name='weekend_seasonality', period=7, fourier_order=3, condition_name='is_weekend')

Отключение стандартной сезонности

# Отключение встроенной сезонности
model = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False
)

# Добавление только нужной сезонности
model.add_seasonality(name='custom_yearly', period=365.25, fourier_order=10)

Обработка выбросов и пропущенных значений

Автоматическая обработка выбросов

def detect_outliers(df, threshold=3):
    """Обнаружение выбросов методом Z-score"""
    z_scores = np.abs((df['y'] - df['y'].mean()) / df['y'].std())
    outliers = df[z_scores > threshold]
    return outliers

# Обнаружение выбросов
outliers = detect_outliers(df)
print(f"Найдено выбросов: {len(outliers)}")

# Замена выбросов на NaN (Prophet обработает автоматически)
df_cleaned = df.copy()
df_cleaned.loc[df_cleaned['y'].isin(outliers['y']), 'y'] = np.nan

Интерполяция пропущенных значений

# Prophet автоматически обрабатывает пропуски, но можно предварительно интерполировать
df_interpolated = df.copy()
df_interpolated['y'] = df_interpolated['y'].interpolate(method='linear')

Кросс-валидация и метрики качества

Временная кросс-валидация

from prophet.diagnostics import cross_validation, performance_metrics

# Кросс-валидация
df_cv = cross_validation(
    model, 
    initial='730 days',    # Начальный период обучения
    period='180 days',     # Шаг валидации
    horizon='365 days'     # Горизонт прогноза
)

# Метрики качества
df_performance = performance_metrics(df_cv)
print(df_performance)

Визуализация кросс-валидации

from prophet.plot import plot_cross_validation_metric

# График метрик по горизонту прогноза
fig = plot_cross_validation_metric(df_cv, metric='mape')
plt.show()

Кастомные метрики

def calculate_custom_metrics(df_cv):
    """Расчет дополнительных метрик"""
    metrics = {}
    
    # Средняя абсолютная процентная ошибка
    metrics['mape'] = np.mean(np.abs((df_cv['y'] - df_cv['yhat']) / df_cv['y'])) * 100
    
    # Коэффициент детерминации
    ss_res = np.sum((df_cv['y'] - df_cv['yhat']) ** 2)
    ss_tot = np.sum((df_cv['y'] - np.mean(df_cv['y'])) ** 2)
    metrics['r2'] = 1 - (ss_res / ss_tot)
    
    # Средняя абсолютная ошибка в масштабе
    metrics['smape'] = np.mean(2 * np.abs(df_cv['y'] - df_cv['yhat']) / 
                              (np.abs(df_cv['y']) + np.abs(df_cv['yhat']))) * 100
    
    return metrics

Интеграция с популярными библиотеками

Интеграция с Scikit-learn

from sklearn.base import BaseEstimator, RegressorMixin
from sklearn.utils.validation import check_X_y, check_array

class ProphetRegressor(BaseEstimator, RegressorMixin):
    """Обертка Prophet для Scikit-learn"""
    
    def __init__(self, **prophet_params):
        self.prophet_params = prophet_params
        self.model = None
    
    def fit(self, X, y):
        df = pd.DataFrame({'ds': X.flatten(), 'y': y})
        self.model = Prophet(**self.prophet_params)
        self.model.fit(df)
        return self
    
    def predict(self, X):
        if self.model is None:
            raise ValueError("Model not fitted yet")
        
        future = pd.DataFrame({'ds': X.flatten()})
        forecast = self.model.predict(future)
        return forecast['yhat'].values

# Использование в пайплайне
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

prophet_regressor = ProphetRegressor(yearly_seasonality=True)
dates = pd.date_range('2020-01-01', periods=len(df), freq='D')
prophet_regressor.fit(dates.values.reshape(-1, 1), df['y'].values)

Интеграция с PyCaret

# Установка PyCaret
# pip install pycaret

# Использование Prophet в PyCaret
from pycaret.time_series import *

# Настройка эксперимента
exp = setup(
    data=df,
    target='y',
    session_id=123,
    train_size=0.8,
    fold_strategy='expanding',
    fold=3
)

# Создание модели Prophet
prophet_model = create_model('prophet')

# Финализация модели
finalized_model = finalize_model(prophet_model)

# Прогноз
predictions = predict_model(finalized_model, fh=30)

Полная таблица методов и функций Prophet

Основные методы класса Prophet

Метод Описание Параметры Возвращаемое значение
__init__() Инициализация модели growth='linear', changepoints=None, n_changepoints=25, changepoint_range=0.8, yearly_seasonality='auto', weekly_seasonality='auto', daily_seasonality='auto', holidays=None, seasonality_mode='additive', seasonality_prior_scale=10.0, holidays_prior_scale=10.0, changepoint_prior_scale=0.05, mcmc_samples=0, interval_width=0.80, uncertainty_samples=1000, stan_backend='PYSTAN' Объект Prophet
fit() Обучение модели df (DataFrame с колонками 'ds' и 'y'), **kwargs Обученная модель
predict() Построение прогноза df (DataFrame с колонкой 'ds') DataFrame с прогнозами
make_future_dataframe() Создание будущих дат periods (int), freq='D', include_history=True DataFrame с датами
add_seasonality() Добавление сезонности name (str), period (float), fourier_order (int), prior_scale=None, mode=None, condition_name=None None
add_regressor() Добавление регрессора name (str), prior_scale=None, standardize='auto', mode=None None
add_country_holidays() Добавление праздников страны country_name (str) None
plot() Построение графика fcst (DataFrame), ax=None, uncertainty=True, plot_cap=True, xlabel='ds', ylabel='y' matplotlib.figure.Figure
plot_components() График компонентов fcst (DataFrame), uncertainty=True, plot_cap=True, weekly_start=0, yearly_start=0 matplotlib.figure.Figure

Вспомогательные функции

Функция Описание Параметры Возвращаемое значение
cross_validation() Кросс-валидация model, horizon, initial=None, period=None, cutoffs=None, disable_tqdm=False DataFrame
performance_metrics() Метрики качества df (результат cross_validation), metrics=None, rolling_window=0.1 DataFrame
plot_cross_validation_metric() График метрик df_cv, metric, rolling_window=0.1 matplotlib.figure.Figure
plot_plotly() Интерактивный график m (модель), fcst (прогноз), uncertainty=True, plot_cap=True, trend=False, changepoints=False, changepoints_threshold=0.01 plotly.graph_objects.Figure
plot_components_plotly() Интерактивные компоненты m (модель), fcst (прогноз), uncertainty=True, plot_cap=True, weekly_start=0, yearly_start=0 plotly.graph_objects.Figure

Параметры конфигурации

Параметр Тип Значение по умолчанию Описание
growth str 'linear' Тип роста: 'linear' или 'logistic'
changepoints list None Даты точек изменения тренда
n_changepoints int 25 Количество потенциальных точек изменения
changepoint_range float 0.8 Доля данных для поиска изменений
yearly_seasonality bool/str 'auto' Годовая сезонность
weekly_seasonality bool/str 'auto' Недельная сезонность
daily_seasonality bool/str 'auto' Дневная сезонность
holidays DataFrame None Таблица праздников
seasonality_mode str 'additive' Режим сезонности: 'additive' или 'multiplicative'
seasonality_prior_scale float 10.0 Регуляризация сезонности
holidays_prior_scale float 10.0 Регуляризация праздников
changepoint_prior_scale float 0.05 Чувствительность к изменениям тренда
interval_width float 0.80 Ширина доверительного интервала
uncertainty_samples int 1000 Количество сэмплов для неопределенности

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

Прогнозирование продаж в e-commerce

def forecast_ecommerce_sales(df):
    """Прогнозирование продаж для интернет-магазина"""
    
    # Добавление праздников
    holidays = pd.DataFrame({
        'holiday': ['Black Friday', 'Cyber Monday', 'New Year Sale'],
        'ds': pd.to_datetime(['2023-11-24', '2023-11-27', '2023-01-01']),
        'lower_window': [-7, -3, 0],
        'upper_window': [1, 1, 7],
    })
    
    # Добавление маркетинговых кампаний
    marketing_events = pd.DataFrame({
        'holiday': 'marketing_campaign',
        'ds': pd.to_datetime(['2023-03-15', '2023-06-15', '2023-09-15']),
        'lower_window': 0,
        'upper_window': 14,
    })
    
    all_holidays = pd.concat([holidays, marketing_events], ignore_index=True)
    
    # Создание модели
    model = Prophet(
        holidays=all_holidays,
        seasonality_mode='multiplicative',  # Мультипликативная сезонность для продаж
        yearly_seasonality=True,
        weekly_seasonality=True,
        daily_seasonality=False
    )
    
    # Добавление регрессоров
    model.add_regressor('marketing_spend')
    model.add_regressor('competitor_price', standardize=True)
    
    # Обучение
    model.fit(df)
    
    # Прогноз на 90 дней
    future = model.make_future_dataframe(periods=90)
    # Заполнение будущих значений регрессоров
    future['marketing_spend'] = np.random.exponential(1000, len(future))
    future['competitor_price'] = np.random.normal(100, 20, len(future))
    
    forecast = model.predict(future)
    
    return model, forecast

Прогнозирование посещаемости веб-сайта

def forecast_website_traffic(df):
    """Прогнозирование трафика веб-сайта"""
    
    # Учет выходных дней
    df['is_weekend'] = df['ds'].dt.dayofweek.isin([5, 6]).astype(int)
    
    # Создание модели
    model = Prophet(
        daily_seasonality=True,
        weekly_seasonality=False,  # Отключаем стандартную недельную сезонность
        yearly_seasonality=True,
        changepoint_prior_scale=0.1  # Более чувствительная модель
    )
    
    # Добавление условной сезонности для рабочих дней и выходных
    model.add_seasonality(
        name='weekly_workdays',
        period=7,
        fourier_order=3,
        condition_name='is_weekend'
    )
    
    # Добавление регрессоров
    model.add_regressor('is_weekend')
    
    # Обучение
    model.fit(df)
    
    # Прогноз на 30 дней
    future = model.make_future_dataframe(periods=30)
    future['is_weekend'] = future['ds'].dt.dayofweek.isin([5, 6]).astype(int)
    
    forecast = model.predict(future)
    
    return model, forecast

Прогнозирование энергопотребления

def forecast_energy_consumption(df):
    """Прогнозирование энергопотребления"""
    
    # Добавление температуры как основного фактора
    model = Prophet(
        yearly_seasonality=True,
        weekly_seasonality=True,
        daily_seasonality=True,
        seasonality_mode='additive'
    )
    
    # Добавление регрессоров
    model.add_regressor('temperature')
    model.add_regressor('humidity')
    model.add_regressor('is_holiday')
    
    # Добавление сезонности для отопительного сезона
    model.add_seasonality(
        name='heating_season',
        period=365.25,
        fourier_order=8,
        condition_name='is_winter'
    )
    
    # Обучение
    model.fit(df)
    
    return model

Оптимизация производительности

Ускорение обучения

# Использование CMDSTAN для больших данных
model = Prophet(stan_backend='CMDSTANPY')

# Сокращение количества сэмплов
model = Prophet(uncertainty_samples=100)

# Агрегация данных для больших датасетов
df_daily = df.groupby(df['ds'].dt.date).agg({'y': 'mean'}).reset_index()
df_daily['ds'] = pd.to_datetime(df_daily['ds'])

Параллельное обучение нескольких моделей

from concurrent.futures import ProcessPoolExecutor
import multiprocessing

def train_prophet_parallel(data_dict):
    """Параллельное обучение моделей Prophet"""
    
    def train_single_model(args):
        name, df = args
        model = Prophet()
        model.fit(df)
        return name, model
    
    # Использование всех доступных ядер
    with ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) as executor:
        results = list(executor.map(train_single_model, data_dict.items()))
    
    return dict(results)

Диагностика и отладка модели

Анализ остатков

def analyze_residuals(model, df, forecast):
    """Анализ остатков модели"""
    
    # Получение исторических прогнозов
    historical_forecast = forecast[forecast['ds'].isin(df['ds'])]
    residuals = df['y'].values - historical_forecast['yhat'].values
    
    # Статистики остатков
    stats = {
        'mean_residual': np.mean(residuals),
        'std_residual': np.std(residuals),
        'min_residual': np.min(residuals),
        'max_residual': np.max(residuals),
        'mae': np.mean(np.abs(residuals)),
        'rmse': np.sqrt(np.mean(residuals**2))
    }
    
    # Визуализация остатков
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    
    # Временной ряд остатков
    axes[0, 0].plot(df['ds'], residuals)
    axes[0, 0].axhline(y=0, color='r', linestyle='--')
    axes[0, 0].set_title('Остатки по времени')
    axes[0, 0].set_xlabel('Дата')
    axes[0, 0].set_ylabel('Остатки')
    
    # Гистограмма остатков
    axes[0, 1].hist(residuals, bins=30, alpha=0.7)
    axes[0, 1].set_title('Распределение остатков')
    axes[0, 1].set_xlabel('Остатки')
    axes[0, 1].set_ylabel('Частота')
    
    # Q-Q plot
    from scipy import stats
    stats.probplot(residuals, dist="norm", plot=axes[1, 0])
    axes[1, 0].set_title('Q-Q график')
    
    # Автокорреляция остатков
    from statsmodels.stats.diagnostic import acorr_ljungbox
    autocorr = [np.corrcoef(residuals[:-i], residuals[i:])[0, 1] for i in range(1, min(40, len(residuals)))]
    axes[1, 1].plot(autocorr)
    axes[1, 1].axhline(y=0, color='r', linestyle='--')
    axes[1, 1].set_title('Автокорреляция остатков')
    axes[1, 1].set_xlabel('Лаг')
    axes[1, 1].set_ylabel('Корреляция')
    
    plt.tight_layout()
    plt.show()
    
    return stats

Проверка точек изменения тренда

def analyze_changepoints(model, forecast):
    """Анализ точек изменения тренда"""
    
    # Получение точек изменения
    changepoints = model.changepoints
    deltas = model.params['delta'].mean(axis=0)
    
    # Создание DataFrame с изменениями
    changepoint_df = pd.DataFrame({
        'changepoint': changepoints,
        'delta': deltas
    })
    
    # Фильтрация значимых изменений
    significant_changes = changepoint_df[np.abs(changepoint_df['delta']) > 0.01]
    
    # Визуализация
    fig, ax = plt.subplots(figsize=(15, 8))
    
    # Основной график
    ax.plot(forecast['ds'], forecast['yhat'], label='Прогноз')
    ax.plot(forecast['ds'], forecast['trend'], label='Тренд', linestyle='--')
    
    # Отметка точек изменения
    for _, row in significant_changes.iterrows():
        ax.axvline(x=row['changepoint'], color='red', linestyle=':', alpha=0.7)
        ax.text(row['changepoint'], ax.get_ylim()[1] * 0.9, 
                f'Δ={row["delta"]:.3f}', rotation=90)
    
    ax.set_title('Точки изменения тренда')
    ax.legend()
    plt.show()
    
    return significant_changes

Сравнение с другими методами прогнозирования

Сравнение с ARIMA

from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_absolute_error, mean_squared_error

def compare_prophet_arima(df, test_size=30):
    """Сравнение Prophet с ARIMA"""
    
    # Разделение данных
    train_df = df[:-test_size]
    test_df = df[-test_size:]
    
    # Prophet
    prophet_model = Prophet()
    prophet_model.fit(train_df)
    
    future = prophet_model.make_future_dataframe(periods=test_size)
    prophet_forecast = prophet_model.predict(future)
    prophet_pred = prophet_forecast['yhat'].tail(test_size).values
    
    # ARIMA
    arima_model = ARIMA(train_df['y'], order=(1, 1, 1))
    arima_fitted = arima_model.fit()
    arima_pred = arima_fitted.forecast(steps=test_size)
    
    # Метрики
    prophet_mae = mean_absolute_error(test_df['y'], prophet_pred)
    prophet_rmse = np.sqrt(mean_squared_error(test_df['y'], prophet_pred))
    
    arima_mae = mean_absolute_error(test_df['y'], arima_pred)
    arima_rmse = np.sqrt(mean_squared_error(test_df['y'], arima_pred))
    
    # Результаты
    comparison = pd.DataFrame({
        'Model': ['Prophet', 'ARIMA'],
        'MAE': [prophet_mae, arima_mae],
        'RMSE': [prophet_rmse, arima_rmse]
    })
    
    return comparison

Часто задаваемые вопросы

Технические вопросы

Что делать, если модель работает медленно?

  • Используйте stan_backend='CMDSTANPY' для больших данных
  • Сократите количество uncertainty_samples
  • Агрегируйте данные до более крупных временных интервалов
  • Уменьшите количество гармоник в сезонности (fourier_order)

Как обрабатывать множественные временные ряды? Prophet не поддерживает мультивариантные ряды напрямую. Необходимо обучать отдельную модель для каждого ряда или использовать внешние библиотеки типа sktime.

Можно ли использовать Prophet для классификации? Нет, Prophet предназначен только для регрессии временных рядов. Для классификации временных рядов используйте специализированные методы.

Практические вопросы

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

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

Как интерпретировать доверительные интервалы? Доверительные интервалы отражают неопределенность модели. Широкие интервалы указывают на высокую неопределенность, узкие - на уверенность модели в прогнозе.

Заключение

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

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

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

Новости