从1.5版本开始,XGBoost Python包为公共测试提供了对分类数据的实验性支持 。对于数值数据,切分条件被定义为 v a l u e < t h r e s h o l d value < threshold value<threshold ,而对于分类数据,切分的定义取决于是否使用分区或独热编码。对于基于分区的切分,切分被指定为 v a l u e ∈ c a t e g o r i e s value \in categories value∈categories,其中categories是一个特征中的类别集。如果使用独热编码,则切分定义为 v a l u e = = c a t e g o r y value == category value==category 。
使用 scikit-learn 进行训练
将分类数据传递给XGBoost的最简单方法是使用数据框和scikit-learn
接口,如XGBClassifier
。为了准备数据,用户需要将输入预测器的数据类型指定为category
。对于pandas/cudf
数据框,可以通过以下方式实现:
python
X["cat_feature"].astype("category")
对于表示分类特征的所有列。之后,用户可以告诉XGBoost启用对分类数据的训练。假设正在使用XGBClassifier
进行分类问题,指定参数enable_categorical
:
python
# 支持的树方法有 `approx` 和 `hist`。
clf = xgb.XGBClassifier(tree_method="hist", enable_categorical=True, device="cuda")
# X 是前面代码片段中创建的数据框
clf.fit(X, y)
# 必须使用 JSON/UBJSON 进行序列化,否则信息将丢失。
clf.save_model("categorical-model.json")
训练完成后,大多数其他特征都可以利用该模型。例如,可以绘制模型并计算全局特征重要性:
python
# 获取图形
graph = xgb.to_graphviz(clf, num_trees=1)
# 获取 matplotlib 轴
ax = xgb.plot_tree(clf, num_trees=1)
# 获取特征重要性
clf.feature_importances_
dask中的scikit-learn
接口与单节点版本类似。基本思想是创建包含category
特征类型的数据框,并通过设置enable_categorical
参数告诉XGBoost使用它。有关在scikit-learn
接口中使用带有独热编码的分类数据的实际示例,请参见使用cat_in_the_dat
数据集进行分类数据的入门。可以在Train XGBoost with cat_in_the_dat dataset中找到使用独热编码数据和XGBoost分类数据支持的比较。
最佳分区Optimal Partitioning
最佳分区是一种用于每个节点拆分的分类预测变量的技术,首次由[1]引入并证明在数值输出方面是最优的。该算法用于决策树[2],后来LightGBM [3]将其引入到梯度提升树的上下文中 ,现在也作为XGBoost的可选功能用于处理分类拆分。具体而言,Fisher [1]的证明表明,当试图基于这些值的度量之间的距离将一组离散值分区为组时,只需要查看排序的分区而不是枚举所有可能的排列 。在决策树的上下文中,离散值是类别,度量是输出叶子值 。直观地说,希望将输出类似叶值的类别分组 。在查找拆分时,**首先对梯度直方图进行排序,以准备连续的分区,然后根据这些排序的值枚举拆分。**XGBoost的相关参数之一是max_cat_to_onehot
,它控制每个特征是使用独热编码还是分区,详见分类特征的参数详情。
使用原生接口Using native interface
scikit-learn
接口对用户非常友好,但缺少仅在原生接口中提供的某些功能。例如,用户无法直接计算SHAP值。此外,原生接口支持更多的数据类型。要在具有分类数据的情况下使用原生接口,我们需要将类似的参数传递给DMatrix
或QuantileDMatrix
和train
函数。对于数据框输入:
python
# X is a dataframe we created in previous snippet
Xy = xgb.DMatrix(X, y, enable_categorical=True)
booster = xgb.train({"tree_method": "hist", "max_cat_to_onehot": 5}, Xy)
# Must use JSON for serialization, otherwise the information is lost
booster.save_model("categorical-model.json")
SHAP值计算:
python
SHAP = booster.predict(Xy, pred_interactions=True)
# categorical features are listed as "c"
print(booster.feature_types)
对于其他类型的输入,例如numpy
数组,可以通过在DMatrix
中使用feature_types
参数来告诉XGBoost有关特征类型:
python
# "q" is numerical feature, while "c" is categorical feature
ft = ["q", "c", "c"]
X: np.ndarray = load_my_data()
assert X.shape[1] == 3
Xy = xgb.DMatrix(X, y, feature_types=ft, enable_categorical=True)
对于数值数据,特征类型可以是"q"
或"float"
,而对于分类特征,则指定为"c"
。XGBoost中的Dask模块具有相同的接口,因此dask.Array
也可以用于分类数据。最后,sklearn接口XGBRegressor
也具有相同的参数。
数据一致性
XGBoost接受参数来指示哪个特征被视为分类特征,可以通过dataframe
的dtypes
或通过feature_types
参数来指定。然而,XGBoost本身不存储关于类别如何编码的信息。例如,给定将音乐流派映射到整数代码的编码模式:
python
{"acoustic": 0, "indie": 1, "blues": 2, "country": 3}
XGBoost不知道输入的映射,因此无法将其存储在模型中。映射通常在用户的数据工程管道中发生,使用像sklearn.preprocessing.OrdinalEncoder
这样的列转换器。为了确保XGBoost的正确结果,用户需要保持在训练和测试数据上一致的数据转换管道。用户应该注意以下错误:
python
X_train["genre"] = X_train["genre"].astype("category")
reg = xgb.XGBRegressor(enable_categorical=True).fit(X_train, y_train)
# invalid encoding
X_test["genre"] = X_test["genre"].astype("category")
reg.predict(X_test)
在上面的代码片段中,训练数据和测试数据被分别编码,导致两个不同的编码模式和无效的预测结果。有关使用序数编码器的示例,请参阅特征工程管道以获取分类数据。
其他注意事项
默认情况下,XGBoost假设输入类别是从0到类别数 [ 0 , n _ c a t e g o r i e s ) [0, n\_categories) [0,n_categories)的整数。然而,由于训练数据集中的错误或缺失值,用户可能提供具有无效值的输入。这可能是负值、无法由32位浮点表示的整数值,或大于实际唯一类别数的值。在训练期间,需要进行验证,但对于预测而言,出于性能原因,它被视为未选择的类别。
参考
-
[1] Walter D. Fisher. "On Grouping for Maximum Homogeneity". Journal of the American Statistical Association. Vol. 53, No. 284 (Dec., 1958), pp. 789-798.
-
[2] Trevor Hastie, Robert Tibshirani, Jerome Friedman. "The Elements of Statistical Learning". Springer Series in Statistics Springer New York Inc. (2001).
-
[3] Guolin Ke, Qi Meng, Thomas Finley, Taifeng Wang, Wei Chen, Weidong Ma, Qiwei Ye, Tie-Yan Liu. "LightGBM: A Highly Efficient Gradient Boosting Decision Tree." Advances in Neural Information Processing Systems 30 (NIPS 2017), pp. 3149-3157.
-
https://xgboost.readthedocs.io/en/latest/tutorials/categorical.html
-
https://www.kaggle.com/code/shahules/an-overview-of-encoding-techniques/notebook