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 строго требует следующую структуру данных:
- Столбец 'ds' — временные метки (datetime)
- Столбец '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 надежным выбором для долгосрочных проектов прогнозирования в различных отраслях - от электронной коммерции и финансов до логистики и энергетики.
Настоящее и будущее развития ИИ: классической математики уже недостаточно
Эксперты предупредили о рисках фейковой благотворительности с помощью ИИ
В России разработали универсального ИИ-агента для роботов и индустриальных процессов