Ответ
Да, модели градиентного бустинга, такие как XGBoost или LightGBM, могут предсказывать отрицательные значения, даже если все целевые переменные в обучающей выборке положительны. Я сталкивался с этим в задачах прогнозирования спроса. Причины:
- Аддитивная природа бустинга: Предсказание — это сумма предсказаний последовательных деревьев. Каждое новое дерево вносит поправку (положительную или отрицательную) к остаткам предыдущего шага. Накопление отрицательных поправок может вывести итоговое значение в отрицательную область.
- Функция потерь: Стандартная регрессия с MSE минимизирует квадрат ошибки и не накладывает ограничений на выход модели.
- Начальное приближение (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). Грубо, но иногда работает. Хотя это, конечно, признак того, что модель где-то лажает конкретно, и лучше бы причину лечить.
Короче, суть в том, что модель — это не физик-ядерщик, она законов природы не знает. Её научили минимизировать ошибку, а она минимизирует. А то, что спрос отрицательным не бывает — это уже твои, человеческие, проблемы. Вот и приходится подкладывать соломку, либо трансформациями, либо выбором правильной функции потерь. Иначе будет тебе хиросима на метриках, а не прогноз.