Может ли градиентный бустинг на деревьях дать отрицательное предсказание при положительной целевой переменной?

Ответ

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

  1. Аддитивная природа бустинга: Предсказание — это сумма предсказаний последовательных деревьев. Каждое новое дерево вносит поправку (положительную или отрицательную) к остаткам предыдущего шага. Накопление отрицательных поправок может вывести итоговое значение в отрицательную область.
  2. Функция потерь: Стандартная регрессия с MSE минимизирует квадрат ошибки и не накладывает ограничений на выход модели.
  3. Начальное приближение (initial prediction): Часто это среднее значение целевой переменной, но алгоритм не гарантирует, что последующие шаги не сдвинут предсказание.

Пример с XGBoost:

import xgboost as xgb
import numpy as np

# Все таргеты положительные
X = np.array([[10], [20], [30], [40]])
y = np.array([15, 25, 35, 45])

model = xgb.XGBRegressor(n_estimators=10, max_depth=3)
model.fit(X, y)

# Предсказание для точки, выходящей за пределы обучающего диапазона по X
print(model.predict(np.array([[5]])))  # Может выдать, например, -2.1

Как с этим бороться в продакшене:

  • Трансформация таргета: Использовать np.log1p(y) для обучения и np.expm1(pred) для обратного преобразования.
  • Специфичные функции потерь: Например, 'reg:gamma' или 'reg:tweedie' в XGBoost для данных, имеющих природу счетов или величин.
  • Постобработка: Применить np.maximum(pred, 0) или порог, если отрицательные значения физически невозможны.

Ответ 18+ 🔞

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

Смотри, в чём тут собака зарыта, а точнее, сука, порода этой проблемы. Модели градиентного бустинга — это же не какая-нибудь хитрая жопа, а аддитивные монстры. Представь: каждое новое деревце — это как очередной мудак, который приходит и говорит: «А вот тут ты, братан, ошибся, давай я поправлю». И поправка может быть как плюсом, так и минусом. И вот если эти поправки-минусы накопятся, как снежный ком, то итоговый прогноз спокойно так улетает в минуса, даже если изначально все цифры были больше нуля. Волнение ебать, когда видишь отрицательный спрос на товар — типа люди тебе ещё и должны будут за то, что забрали его с полки?

Функция потерь, та же MSE, ей вообще похуй, положительное у тебя значение или нет. Её дело — квадрат ошибки минимизировать, а не в рамки физического смысла укладываться. Ну и начальное приближение, от которого весь этот цирк начинается, — обычно среднее по выборке. Но алгоритм же не святая вода, он не гарантирует, что не уведёт тебя в дебри.

Вот смотри на этот кусок кода, тут всё как на ладони:

import xgboost as xgb
import numpy as np

# Все таргеты положительные
X = np.array([[10], [20], [30], [40]])
y = np.array([15, 25, 35, 45])

model = xgb.XGBRegressor(n_estimators=10, max_depth=3)
model.fit(X, y)

# Предсказание для точки, выходящей за пределы обучающего диапазона по X
print(model.predict(np.array([[5]])))  # Может выдать, например, -2.1

Видишь? Обучали на положительных числах, а спросили для значения X=5, которое за границами обучающей выборки лежит, — и получи, ебать мои старые костыли, минус 2.1. Модель просто экстраполирует, как умеет, а умеет она через пень-колоду.

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

  • Трансформация таргета. Самый распространённый финт. Берёшь y, делаешь np.log1p() (это чтобы с нулями не облажаться), обучаешь модель на этих логарифмах. А потом, когда предсказываешь, делаешь обратную операцию — np.expm1(). Это почти всегда вытягивает предсказания в положительную зону, потому что экспонента — она ж не отрицательная.
  • Специфичные функции потерь. Не надо тут изобретать велосипед. В том же XGBoost смотри: 'reg:gamma' или 'reg:tweedie'. Они как раз заточены под данные, которые по природе своей положительные (счета, количества, спрос). Они будут неохотно уходить в минус.
  • Постобработка — метод топора. Если отрицательные значения физически невозможны (ну не может быть минус три штуки товара на складе), то после предсказания просто обрезаешь всё, что ниже нуля: np.maximum(pred, 0). Грубо, но иногда работает. Хотя это, конечно, признак того, что модель где-то лажает конкретно, и лучше бы причину лечить.

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