Всем привет! Я Никита, продуктовый аналитик сервиса путешествий Туту. Я работаю в команде отелей — это сервис бронирования жилья, где особенно важно учитывать сезонность. Спрос на поездки меняется резко: в майские праздники и в августе происходит всплеск количества бронирований, в ноябре или марте — провалы. При этом точность прогноза для бизнеса критична: от нее зависят маркетинговые бюджеты, работа с партнёрами и планы по продажам.

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

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

Почему именно Prophet

Перед выбором инструмента мы определились с требованиями:

  • простота использования — не хотелось тратить недели на внедрение;

  • возможность быстро учесть сезонность и тренды;

  • гибкость через добавление регрессоров;

  • лёгкая автоматизация для запуска в продакшене.

Мы пробовали разные подходы. Классические модели вроде ARIMA и SARIMA оказались слишком капризными: они дают хорошие прогнозы, но требуют долгого подбора параметров и плохо масштабируются, когда рядов сотни или тысячи. Holt-Winters прост в использовании, но работает только на относительно стабильных паттернах и не справляется со сложной сезонностью. Современные библиотеки вроде Darts или Kats дают доступ к нейросетям и state-of-the-art методам, но они перегружены для нашей задачи: запускать их в продакшн дороже и сложнее, чем хотелось бы.

На этом фоне Prophet оказался оптимальным компромиссом: он прост в настройке, учитывает сезонность и праздники, быстро даёт результат и не требует глубоких знаний в статистике или ML.

Он закрыл большинство наших задач «из коробки» и позволил быстро построить MVP. Изначально проект задумывался как небольшой внутренний инструмент для аналитиков, но со временем перерос в полноценную систему генерации прогнозов для бизнеса с интеграцией в дашборды.

MVP: быстрый старт

Для начала разберемся, за что отвечают основные параметры в Prophet:

  • сhangepoint_prior_scale — отвечает за чувствительность модели к изменениям тренда. Чем выше значение, тем гибче модель реагирует на изменения, но при этом растёт риск переобучения. Малые значения делают модель более «гладкой», но она может пропускать важные изменения.

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

  • holidays_prior_scale — контролирует, насколько сильно праздники будут влиять на прогноз. Если значение слишком маленькое, эффект праздников почти не будет учитываться.

  • n_changepoints — количество потенциальных точек излома тренда. Если данных много и тренд часто меняется, полезно увеличить.

  • changepoint_range — доля временного ряда, в пределах которого Prophet ищет точки изменения тренда. По умолчанию 0.8 — то есть 80% первых данных. Если важны недавние тренды, нужно увеличить параметр до 0.9–0.95.

Мы начали с максимально простого варианта:

from clickhouse_driver import Client
from prophet import Prophet
import pandas as pd
# Подключение к БД (пример)
client = Client(host="...", port=9000, user="...", password="...", database="...")
# Загружаем данные
sql = """
select date_trunc('day', date) as ds,
       count(id) as y
from table
"""
data = client.query_dataframe(sql)
# Обучение модели
model = Prophet()
model.fit(data)
# Создаем будущие даты
future = pd.DataFrame({'ds': pd.date_range(start="2023-01-01", end="2023-12-31", freq='D')})
forecast = model.predict(future)
# Мы получили прогноз, который сразу же можно визуализировать:

fig1 = model.plot(forecast)
fig2 = model.plot_components(forecast)

В результате получили график прогноза с MAPE ~27%. На графике заметно, что «из коробки» Prophet справляется не всегда: он сглаживает пики высокого сезона и недооценивает реальный рост, а в низкий сезон наоборот держит прогноз выше фактического уровня. Отдельные резкие всплески тоже остаются вне предсказаний — для таких случаев нужны дополнительные фичи или настройка модели.

Такого результата явно недостаточно для продакшн-использования. Но уже на этом шаге мы посмотрели, как Prophet разложил ряд на тренд и сезонность. Мы сразу увидели долгосрочный рост спроса, недельный паттерн с пиком в середине недели и провалом в воскресенье, а также ярко выраженный летний сезон с пиками в июле–августе и спадом в начале года.

Проблемы на пути

Первый пайплайн выглядел следующим образом:

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

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

Разбор показал, что главная причина — жёстко зафиксированные гиперпараметры. Они работали на исторических данных, но ломались при изменении структуры временного ряда. Нужно было решение, которое позволило бы модели адаптироваться к новым условиям.

Оптимизируем гиперпараметры

Чтобы избежать переобучения, мы подключили Optuna. Эта библиотека автоматически подбирает гиперпараметры модели, минимизируя ошибки. 

Пример работы:

import optuna
def objective(trial):
    cps = trial.suggest_float("changepoint_prior_scale", 0.001, 0.5, log=True)
    sps = trial.suggest_float("seasonality_prior_scale", 0.01, 10.0)
    
    model = Prophet(
        changepoint_prior_scale=cps,
        seasonality_prior_scale=sps,
        holidays=holidays_df
    )
    model.fit(data)
    forecast = model.predict(future)
    return mean_absolute_percentage_error(data['y'], forecast['yhat'][:len(data)])
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=50)

С Optuna модель стала стабильнее, а прогнозы — ближе к реальности. В пайплайне появился еще один блок — оптимизация. Из-за него нам пришлось изменить структуру хранения данных и добавить таблицу для сохранения гиперпараметров: дата, метрика, параметры, функция потерь. 

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

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

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

Новый пайплайн выглядит так:

Продакшн и автоматизация

После всех обновлений модель уже крутилась автоматически. Но для перевода в продакшн и реальной помощи бизнесу нам пришлось её ещё доработать.

Вот что мы добавили.

Хранение результатов прогнозов. Все прогнозы сохраняются в отдельной таблице ClickHouse. Для каждой итерации фиксируется прогноз, дата загрузки и служебный тег. Храним все версии без перезаписи. Это позволяет сравнивать прогнозы с фактами и возвращаться к любой версии.

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

Мониторинг качества. Сделали дашборд для анализа прогнозов в динамике. На нём отображаются ключевые метрики: например, MAPE и RMSE. Можно сравнивать итерации, отслеживать деградацию или улучшение модели.

Теперь система работает без ручного вмешательства и поддерживает rolling forecast, а бизнес с его помощью может планировать показатели на квартал или следующий год. При этом стартовой точкой был «голый» объект Prohpet с MAPE 27%, но доработки и использование более оптимальных параметров позволили нам приблизиться к MAPE в 6%. Удалось увеличить точность в ~3.5 раза.


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

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

Самый главный вывод — нужно не бояться ошибок. MVP с MAPE 27% и отрицательными прогнозами сначала показался нам провалом, но именно через такие эксперименты рождаются рабочие решения. Сегодня у нас есть система, которая ежедневно обновляет прогнозы, хранит их историю и помогает бизнесу принимать решения.

Если интересно посмотреть полный пайплайн и код — мы выложили его на GitHub.

Комментарии (0)