XGBoost销量预测自定义目标函数:如何传入销售价格参数?
解决XGBoost自定义目标函数中传入销售价格的问题
首先看你遇到的IndexError,根源是代码里price = train[0]["salesPrice"]只取了单个样本的销售价格,得到的是长度为1的数组(甚至是标量),而mask1、mask2是对应整个训练集长度(136019个样本)的布尔索引,用长度为1的数组去索引长度136019的数组,自然会报长度不匹配的错误。
而且你的目标函数注释里提到dtrain is a numpy array,这说明你没有用XGBoost的DMatrix封装数据——这才是无法传入销售价格的核心问题:DMatrix是XGBoost用来存储训练数据、标签和附加信息的容器,只有用它才能把销售价格这类额外特征传递到自定义目标函数中。
正确的实现步骤
1. 用DMatrix封装数据并存储销售价格
在创建训练数据矩阵时,把销售价格作为附加信息存入DMatrix:
import xgboost as xgb import numpy as np from typing import Union, Tuple # 假设X_train是特征矩阵,y_train是销量标签,train["salesPrice"]是对应样本的销售价格数组 dtrain = xgb.DMatrix(X_train, label=y_train) # 将销售价格存入DMatrix的自定义信息字段 dtrain.set_info(price=train["salesPrice"].values)
2. 修改自定义目标函数,从DMatrix中获取价格
调整目标函数,通过dtrain.get_float_info()获取存储的销售价格数组:
def monetary_value_objective(predt: np.ndarray, dtrain: xgb.DMatrix) -> Tuple[np.ndarray, np.ndarray]: """ predt: 模型预测值数组 dtrain: XGBoost DMatrix对象,包含标签和附加的销售价格 """ y = dtrain.get_label() # 获取真实销量标签 price = dtrain.get_float_info('price') # 获取存储的销售价格数组 mask1 = predt <= y # 预测值小于等于真实值(预测过少) mask2 = predt > y # 预测值大于真实值(预测过多) # 计算梯度 grad = price ** 2 * (predt - y) grad[mask1] = 2 * grad[mask1] grad[mask2] = 0.72 * grad[mask2] # 计算二阶导数(Hessian) hess = np.empty_like(grad) hess[mask1] = 2 * price[mask1] ** 2 hess[mask2] = 0.72 * price[mask2] ** 2 # XGBoost默认是最小化损失函数,这里将梯度取负(根据你的损失定义调整) grad = -grad return grad, hess
3. 训练模型时指定自定义目标函数
训练时使用你定义的目标函数,注意要传入DMatrix格式的dtrain:
params = { 'objective': 'reg:squarederror', # 这里虽然指定,但会被自定义目标覆盖,也可以设为'objective': 'reg:linear'(但已废弃) # 其他超参数... } model = xgb.train(params, dtrain, num_boost_round=100, obj=monetary_value_objective)
关于需求的可行性
你的需求完全可行:XGBoost设计时就支持自定义目标函数访问DMatrix中的附加信息,只要通过set_info存入、get_float_info/get_int_info等方法取出,就能在目标函数中使用样本级别的额外特征(比如这里的销售价格)来计算个性化的损失、梯度和二阶导数。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

