Всем привет! Меня зовут Никита Жарков, я продуктовый аналитик с большим опытом работы в Edtech и банковской сфере. В этой статье я расскажу, как мы построили систему прогнозирования прямо внутри ClickHouse, и покажу, как вы можете сделать подобное у себя. Здесь будет не только история как мы сделали, но и понятный путь, который можно повторить шаг за шагом: от подготовки данных до проверки качества.

Обычно прогнозы строят через внешний стек - выгрузка, Python, отдельные пайплайны. Это нормально, но не всегда удобно, особенно если прогнозы нужны ежедневно и команда хочет держать всё в одном месте. Мы решили использовать встроенные ML‑функции ClickHouse и получить рабочий прогноз без внешней инфраструктуры. В статье разберём, почему это работает, какие признаки нужны, как устроено обучение и как правильно оценить качество результата.

Зачем прогнозировать внутри ClickHouse

Суть подхода в том, что ClickHouse уже умеет обучать простые модели. Мы не изобретаем собственный ML‑стек, не тянем новые сервисы и не держим отдельные пайплайны. Мы используем встроенные функции и получаем прогноз на месте, там же, где живут данные. Это снимает массу проблем - от поддержки внешнего окружения, до гонки версий и повторяемости результата. Если вы хотите повторить подход у себя, это главный принцип: максимум логики - внутри ClickHouse.

Процесс прогнозирования достаточно быстрый и простой в реализации, чем его собратья.
Процесс прогнозирования достаточно быстрый и простой в реализации, чем его собратья.

Что именно прогнозируем

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

Как устроена архитектура

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

Признаки: тренд и сезонность

Линейная регрессия не понимает время сама по себе, поэтому мы даём ей признаки. Первый - тренд, то есть нормализованное время от 0 до 1, которое показывает положение наблюдения внутри исторического периода. Это позволяет модели увидеть общий наклон: растёт метрика или падает. Второй блок - сезонность. Для денег мы используем дни недели, для пользователей и авторов - месяцы. Категории кодируем с помощью бинарных признаков, чтобы модель могла учить отдельные коэффициенты на каждый день или месяц. Этот шаг легко повторить для любой сезонности: недели, месяцы, кварталы, праздники - всё зависит от вашей метрики.

Внутри запроса на потребуется определить начало и конец нашего исторического периода, чтобы тренд понимал какой диапазон дат участвует. В таргет добавляем нашу метрику и в свободном формате оставляем наше поле с датой.
Внутри запроса нам потребуется определить начало и конец нашего исторического периода, чтобы тренд понимал какой диапазон дат участвует. В таргет добавляем нашу метрику и в свободном формате оставляем наше поле с датой.
На выходе у нас получается таблица с нормализованным временем (Trend) от 0 до 1, где 0 – начало нашего исторического периода, 1 конец. Фактически это линейный тренд, который показывает общую динамику роста или падения.
На выходе у нас получается таблица с нормализованным временем (Trend) от 0 до 1, где 0 – начало нашего исторического периода, 1 конец. Фактически это линейный тренд, который показывает общую динамику роста или падения.

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

Денежные метрики почти всегда имеют длинный хвост: много дней со средними значениями и немного с очень высокими. Поэтому мы логарифмируем целевую переменную. Это сжимает шкалу и делает распределение более симметричным, что сильно помогает линейной модели. В ClickHouse это выглядит как log(money + 1) на этапе обучения и exp(prediction) - 1 на этапе прогноза. Если у вас любая метрика с похожим хвостом, этот приём почти всегда даёт заметное улучшение.

Как обучаем модель

Обучение делается функцией stochasticLinearRegressionState. У неё четыре параметра: скорость обучения, регуляризация, количество эпох и метод оптимизации. Скорость обучения - это шаг при градиентном спуске. Большой шаг быстрее, но рискованнее, маленький - стабильнее, но медленнее. Регуляризация - это защита от переобучения: модель штрафуется за слишком большие веса. Эпохи - сколько раз модель проходит весь набор данных. Оптимизатор SGD - стандартный, простой и достаточно надёжный. Рекомендую на старте не тюнить слишком глубоко: выберите базовую конфигурацию и посмотрите на качество, а затем уже двигайтесь по параметрам.

Обучаем модель и возвращаем ее веса
Обучаем модель и возвращаем ее веса
Применяем обученную модель к новым данным
Применяем обученную модель к новым данным

Прогнозирование и коррекция

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

Почему не ARIMA/Prophet/CatBoost

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

Качество и тюнинг параметров

На первом прогоне мы увидели MAPE (как часто мы ошибаемся) = 10,12%. Это неплохой результат, но если мы говорим про деньги, то нам нужна точность выше. Дальше начинается тюнинг. Уже простая смена параметров дала заметный прогресс. Например, конфигурация stochasticLinearRegressionState(0.3, 0.001, 20, 'SGD') снизила MAPE до 7,44%. А в конечном итоге нам удалось добиться средней ошибки до 5,67%. Это подчёркивает, что параметры сильно влияют на итоговую точность, и именно здесь скрыт большой потенциал улучшений. Практически совет прост: фиксируйте базу, меняйте один параметр за раз и смотрите на резуль��ат.

MAPE – это средняя абсолютная процентная ошибка. Он показывает, в среднем на сколько процентов наш прогноз отличается от фактического значения
MAPE – это средняя абсолютная процентная ошибка. Он показывает, в среднем на сколько процентов наш прогноз отличается от фактического значения

Что можно улучшить дальше

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

Итоги

Мы построили рабочую систему прогнозирования полностью внутри ClickHouse. Она не требует внешней инфраструктуры, работает быстро, прозрачно объясняется и даёт качество, которое можно улучшать по мере необходимости. Это не академическая модель, а практичный инструмент, который можно внедрить в любой аналитический контур уже сегодня, как мы это и сделали внутри Superset.