Как обучить модель предсказывать распределение, а не одно число?

Ответ

Для предсказания полного распределения вместо точечной оценки я использовал несколько подходов в зависимости от задачи:

  1. Квантильная регрессия (например, с Gradient Boosting) для получения доверительных интервалов:

    from sklearn.ensemble import GradientBoostingRegressor
    
    # Обучаем отдельные модели для разных квантилей
    quantiles = [0.05, 0.25, 0.5, 0.75, 0.95]
    models = {}
    for q in quantiles:
        model = GradientBoostingRegressor(loss='quantile', alpha=q, n_estimators=100)
        model.fit(X_train, y_train)
        models[q] = model
    
    # Предсказание: для каждого объекта получаем 5 квантилей
    predictions = {q: models[q].predict(X_test) for q in quantiles}
  2. Модели, предсказывающие параметры распределения (Probabilistic Forecasting). Например, в задаче прогнозирования спроса я применял:

    • Gaussian Process Regression (через sklearn.gaussian_process) — модель предсказывает среднее и дисперсию нормального распределения.
    • Bayesian Neural Networks (Pyro/PyMC3) — получаем апостериорное распределение весов, что даёт распределение предсказаний.
  3. Генеративные модели для сложных непараметрических распределений:

    • Conditional Variational Autoencoder (CVAE) — обучал для генерации возможных сценариев временных рядов.
    • Normalizing Flows (через nflows или Pyro) — для моделирования сложных многомодальных распределений.

Критерии оценки: Для сравнения таких моделей я использовал Continuous Ranked Probability Score (CRPS) — он измеряет расстояние между предсказанным и истинным распределением. Также проверял покрытие доверительных интервалов (например, 90% интервал должен содержать ~90% истинных значений).

Ответ 18+ 🔞

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

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

Первое, что в голову приходит — это квантильная регрессия. Ну, это когда ты не одну модель учишь, а сразу несколько, каждая на свой персентиль. Типа, одна модель отвечает за пессимистичный сценарий (5-й процентиль), другая — за медиану (50-й), третья — за оптимистичный (95-й). В итоге получаешь не точку, а целый веер возможных исходов. Выглядит это примерно так, блядь:

from sklearn.ensemble import GradientBoostingRegressor

# Задаём квантили, которые нам интересны — от пессимиста до оптимиста
quantiles = [0.05, 0.25, 0.5, 0.75, 0.95]
models = {}
for q in quantiles:
    # Тут главное loss='quantile' и alpha выставить правильно
    model = GradientBoostingRegressor(loss='quantile', alpha=q, n_estimators=100)
    model.fit(X_train, y_train)
    models[q] = model

# А потом для каждой новой штуковины получаешь целую пачку предсказаний
predictions = {q: models[q].predict(X_test) for q in quantiles}

Получается такой себе статистический сэндвич: с одной стороны — нижняя булка (5%), посередине — котлета (медиана), сверху — верхняя булка (95%). И всё это вместе — уже не бутерброд, а целый бургер с интервалом.

Второй подход — это когда модель сама, хитрая жопа, параметры распределения предсказывает. Ну, например, не просто число, а сразу и среднее, и разброс. Это как если бы ты спросил: «Сколько будет?», а тебе в ответ: «Ну, в среднем 100, но плюс-минус 20, и вообще распределение нормальное». Для этого овердохуища подходят Гауссовские процессы или байесовские нейронки. Первые тебе сразу mean и std выдают, вторые — вообще всю кашу из возможных весов, из которой потом можно хоть какие симуляции нагенерировать.

Ну и третий, самый навороченный вариант — это генеративные модели. Вот тут уже полный пиздец и магия, чувак. Берёшь, например, Conditional Variational Autoencoder (CVAE) — и он тебе не число рисует, а целые возможные сценарии, как будет выглядеть временной ряд в будущем. Или Normalizing Flows — эта штука умеет самые заковыристые, многогорбые распределения моделировать. Выглядит это всё, конечно, красиво, но и возни с ними — ядрёна вошь.

А как всё это богатство оценивать-то? Вот тут классический MSE уже не катит, потому что он про среднее, а не про распределение. Поэтому берём Continuous Ranked Probability Score (CRPS). Эта метрика, грубо говоря, меряет, насколько твоё предсказанное распределение в среднем «далеко» от реального значения. Чем меньше — тем лучше. Ещё смотрю на покрытие доверительных интервалов: если я сказал, что с вероятностью 90% истинное значение попадёт в мой интервал, то так оно и должно быть в ~90% случаев на тесте. Если покрытие 70% — значит, модель слишком самоуверенная, интервалы узковаты. Если 99% — значит, она просто всех пугает и интервалы как у слона в посудной лавке.

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