XGBoost 分类变量:虚拟化与编码

Posted

技术标签:

【中文标题】XGBoost 分类变量:虚拟化与编码【英文标题】:XGBoost Categorical Variables: Dummification vs encoding 【发布时间】:2016-03-19 19:40:28 【问题描述】:

使用XGBoost时,我们需要将分类变量转换为数值。

以下方法在性能/评估指标上是否存在差异:

    虚拟化分类变量 对分类变量进行编码,例如(a,b,c) 到 (1,2,3)

还有:

是否有任何理由不使用方法 2,例如使用 labelencoder

【问题讨论】:

“在使用 XGBoost 时,我们需要将分类变量转换为数值。” 并非总是如此。如果booster=='gbtree'(默认值),那么XGBoost 可以直接处理编码为数字的分类变量,而不需要哑化/one-hotting。而如果标签是字符串(不是整数),那么是的,我们需要对其进行转换。 @smci 虽然这是真的,但我相信保留了数字关系。因此,在 1 = 德克萨斯和 2 = 纽约的示例中,纽约会“更大”,这是不正确的。 【参考方案1】:

xgboost 只处理数字列。

如果你有一个特征 [a,b,b,c] 描述一个分类变量(即没有数字关系

使用LabelEncoder,您将拥有以下内容:

array([0, 1, 1, 2])

Xgboost 会错误地将此功能解释为具有数字关系!这只是将每个字符串 ('a','b','c') 映射到一个整数,仅此而已。

正确方法

使用OneHotEncoder 你最终会得到这个:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

这是xgboost 或任何其他机器学习工具的分类变量的正确表示

Pandas get_dummies 是一个很好的创建虚拟变量的工具(我认为它更容易使用)。

上述问题中的方法 #2 无法正确表示数据

【讨论】:

这难道不会使类别多的特征看起来比类别少的特征更重要吗? 假设我们正在讨论将 Xgboost 用于 GBDT 而不是线性模型,这个答案根本不正确。使用整数对分类变量进行编码适用于 xgboost,有时 (YMMV) 输出会执行一次热编码。 对于那些声称基于树的拆分算法可以梳理出编码为数字的分类的人,他们需要了解 xgboost 使用基于梯度的拆分标准,因此保留了数字关系,这与基于熵的数字关系不同编码可以更容易成功。这可以通过玩具数据集进行经验验证。如果您有大量类别,那么一个热门当然是一个糟糕的策略。 @B_Miner 你能进一步解释一下吗?我真的很想知道与单热编码的分类特征相比,使用 LabelEncoding 的模型实际上表现如何更好?只是看起来不对 - 我们如何向企业解释这种行为?我的类别有大约 3000 个不同的值,所以 one-hot 编码也使数据集膨胀。 "...或任何其他机器学习工具" 我不了解 xgboost,但总的来说这根本不是真的,许多机器学习工具处理分类变量直接使用 OHE 或虚拟变量会严重降低性能:roamanalytics.com/2016/10/28/…。此外,分类变量还有许多其他编码方案,最佳编码取决于您的模型和数据。【参考方案2】:

我想回答这个问题的不仅仅是 XGBoost,还有处理分类数据的任何问题。虽然“虚拟化”创建了一个非常稀疏的设置,特别是如果您有多个具有不同级别的分类列,标签编码通常是有偏差的,因为数学表示不能反映级别之间的关系。

对于二元分类问题,在传统信用评分模型中高度利用的一种天才但尚未探索的方法是使用证据权重来代替分类级别。基本上每个分类级别都被 proportion of Goods/Proportion of Bads 所取代。

可以阅读更多关于它的信息here。

Python 库here。

此方法允许您捕获一列下的“级别”,并避免通过虚拟化或编码发生的稀疏性或诱导偏差。

希望这会有所帮助!

【讨论】:

这似乎是添加新功能以替代有问题的分类变量的需要的好方法。它仍然不包含与原始列相同的信息,但添加足够多的此类列可以解决问题。 这似乎与更通用的目标编码及其变体非常相似(例如,参见this)【参考方案3】:

这是一个将 One hot encodings 列添加到具有分类列的 Pandas DataFrame 的代码示例:

ONE_HOT_COLS = ["categorical_col1", "categorical_col2", "categorical_col3"]
print("Starting DF shape: %d, %d" % df.shape)


for col in ONE_HOT_COLS:
    s = df[col].unique()

    # Create a One Hot Dataframe with 1 row for each unique value
    one_hot_df = pd.get_dummies(s, prefix='%s_' % col)
    one_hot_df[col] = s

    print("Adding One Hot values for %s (the column has %d unique values)" % (col, len(s)))
    pre_len = len(df)

    # Merge the one hot columns
    df = df.merge(one_hot_df, on=[col], how="left")
    assert len(df) == pre_len
    print(df.shape)

【讨论】:

【参考方案4】:

2020 年 11 月 23 日

XGBoost 自 1.3.0 版起添加了对分类特征的实验性支持。来自文档:

1.8.7 分类数据

除了用户执行编码,XGBoost 有实验性支持 对于使用 gpu_histgpu_predictor 的分类数据。没有特别的 需要对输入的测试数据进行操作,因为信息 about categories 在训练期间被编码到模型中。

https://buildmedia.readthedocs.org/media/pdf/xgboost/latest/xgboost.pdf

在 DMatrix 部分,文档还说:

enable_categorical(布尔值,可选)- 1.3.0 版中的新功能。

专门针对分类特征的实验性支持。不要 设置为 True 除非您对开发感兴趣。目前是 仅适用于 1 vs rest (one hot) 的 gpu_hist 树方法 分类分裂。此外,JSON 序列化格式、gpu_predictor 和 熊猫输入是必需的。

【讨论】:

以上是关于XGBoost 分类变量:虚拟化与编码的主要内容,如果未能解决你的问题,请参考以下文章

在 XGboost 中呈现数字分类数据(特别是一天中的小时)变量的正确方法是啥?

XGBoost/CatBoost中具有大量类别的分类变量

XGBoost/CatBoost中具有大量类别的分类变量

R语言使用R基础安装中的glm函数构建乳腺癌二分类预测逻辑回归模型分类预测器(分类变量)被自动替换为一组虚拟编码变量summary函数查看检查模型使用table函数计算混淆矩阵评估分类模型性能

R语言构建xgboost模型:特征因子化独热编码( one-hot encoding)卡方检验判断预测变量与目标变量的相关性

2万字阐述-Python 用 XGBoost 进行梯度提升的数据准备(收藏)