Вопрос или проблема
У меня проблема с пользовательскими функциями потерь в xgboost: я не могу получить последовательные прогнозы. Другими словами, масштаб моих прогнозов не соответствует значениям, которые я хотел бы предсказать. Я попробовал многие пользовательские функции потерь, но всегда получаю одну и ту же проблему.
import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.datasets import make_regression
n_samples_train = 500
n_samples_test = 100
n_features = 200
X, y = make_regression(n_samples_train, n_features, noise=10)
X_test, y_test = make_regression(n_samples_test, n_features, noise=10)
param = {'verbosity': 1,
'max_depth': 12,
'learning_rate': 0.01,
'nthread': 3,
}
dtrain = xgb.DMatrix(X, y)
best_nrounds = 50
bst_reglinear = xgb.train(param,
dtrain,
best_nrounds)
def reg_obj(preds, dtrain):
y = dtrain.get_label()
N = len(y)
#residual = (preds-y).astype("float")
grad = 2*preds-y
hess = 2*N*np.ones(len(y))
return grad, hess
bst_custom = xgb.train(param,
dtrain,
best_nrounds,
obj=reg_obj)
dtest = xgb.DMatrix(X_test)
pred = bst_reglinear.predict(dtest)
print(np.abs(pred).mean())
pred_custom = bst_custom.predict(dtest)
print(np.abs(pred_custom).mean())
Я думаю, что ваш градиент и гессиан неправильно посчитаны, попробуйте:
grad = 2*(preds-y)
hess = 2*np.ones(len(y))
Ответ или решение
Проблема, с которой вы столкнулись, связана с нестабильностью прогнозов при использовании пользовательской функции потерь (loss function) в XGBoost. Давайте проанализируем вашу ситуацию более подробно и обсудим, как это можно исправить.
Описание проблемы
Ваши прогнозы не находятся в согласии с действительными значениями, и в результате вы получаете результаты, которые не отражают ожидаемую шкалу. Вы пробовали различные пользовательские функции потерь, но всё равно сталкиваетесь с одной и той же проблемой. Это часто связано с неправильно рассчитанными градиентами и гессианами в вашей пользовательской функции.
Анализ пользовательской функции потерь
Ваша текущая реализация функции потерь выглядит следующим образом:
def reg_obj(preds, dtrain):
y = dtrain.get_label()
N = len(y)
grad = 2*preds - y
hess = 2*N*np.ones(len(y))
return grad, hess
В этой реализации вы извлекаете метки y
из dtrain
, а затем вычисляете градиенты и гессианы. Исходная форма градиентов (grad
) выглядит правильно, однако, при вычислении гессианов вы используете N
, что может неправильно масштабировать ваши значения.
Рекомендации по улучшению пользовательской функции потерь
Вместо использования hess = 2*N*np.ones(len(y))
, попробуйте использовать просто константу, как предложили в комментарии. Ваш обновлённый код функции может выглядеть следующим образом:
def reg_obj(preds, dtrain):
y = dtrain.get_label()
grad = 2 * (preds - y)
hess = 2 * np.ones(len(y))
return grad, hess
Применение изменений в XGBoost
После внесенных изменений, повторите процесс обучения модели с использованием ваших данных. Убедитесь, что у вас правильно определены параметры для обучения и выборки данных:
bst_custom = xgb.train(param,
dtrain,
best_nrounds,
obj=reg_obj)
Верификация прогнозов
После обучения вашей модели с обновленной функцией потерь, проведите проверку, чтобы убедиться, что предсказания имеют приемлемую согласованность с фактическими значениями. Вы можете использовать среднее абсолютное значение предсказаний для оценки качества модели:
pred_custom = bst_custom.predict(dtest)
print(np.abs(pred_custom).mean())
Заключение
Проблема, с которой вы столкнулись, скорее всего связана с неправильным вычислением градиентов и гессианов в вашей пользовательской функции потерь. Попробуйте обновленный вариант функции и протестируйте, улучшилась ли стабильность и согласованность ваших прогнозов. При дальнейшем анализе может оказаться полезным изучение влияния других гиперпараметров и использование раннего останова (early stopping) для избежания переобучения модели.
Если после всех рекомендаций проблема останется, возможно, потребуется более глубокий анализ данных, который вы используете для обучения модели.