CatBoost 是如何做特征选择的?

特征选择是指从最相关的特征中选择一个子集进行模型训练的过程。特征选择是非常有用的,原因在于:

  • 简化模型解释

  • 减轻过拟合

  • 减少训练时间

  • 减少内存消耗

特征选择算法

特征选择技术可以分为几组:

  • 包装法 - 基于训练模型的权重/系数消除特征。

  • 过滤法 - 基于一些统计数据以及特征与目标变量之间的相关性来消除特征(无需训练模型)。

  • 嵌入法 - 在模型训练期间消除特征,例如,通过应用 L1 正则化。

CatBoost 实现了一种包装法——递归特征消除。该算法包含以下步骤:

  1. 获取具有所有特征的数据集 D。

  2. 使用数据集 D 训练模型。

  3. 从经过训练的模型中获取每个特征的分数。

  4. 消除数据集 D 中得分最差的几个特征。

  5. 如果需要,返回第 2 步(通常执行特定次数或在损失函数变得更好时)。

特征分数

CatBoost 如何计算特征的分数?这里我们一起学习几种选择。

基于预测值变化

对于每个特征,PredictionValuesChange 显示如果特征值发生变化,预测平均会发生多少变化。重要性值越大,平均而言,如果该特征发生变化,预测值的变化就越大。

计算原理

比较的叶子对在这些叶子路径上的节点中具有不同的分割值。如果满足分裂条件(这个条件取决于特征F),则对象进入左子树;否则它会转到右边的那个。

402 Payment Required

402 Payment Required

  • 分别表示左右叶子中对象的总权重。如果没有为数据集指定权重,则此权重等于每个叶子中的对象数。

  • 分别表示左右叶子中的公式值。

如果模型不是使用单个输入特征本身,而是使用特征的组合,则计算并输出这些特征的平均特征重要性。例如,该模型使用特征 f54c56f77 的组合。首先,计算这些特征组合的特征重要性。然后将结果值除以3并分配给每个特征。

如果模型既单独使用一个特征又与其他特征组合使用,则该特征的总重要性值使用以下公式定义:

  • 402 Payment Required

    是第 j 个特征的个体特征重要性。
  • 402 Payment Required

    是第 i 个组合特征中第 j 个特征的平均特征重要性。
特点
  • 非常快

  • 大的预测值变化并不总是意味着大的损失值变化

  • 不适合排名损失函数

基于损失函数变化

每个输入特征的单独重要性值( 排名指标的默认特征重要性计算方法)。这种类型的特征重要性可用于任何模型,但对模型排名特别有用,因为其他特征重要性类型可能会产生误导性结果。

对于每个特征,该值表示具有该特征和没有该特征的模型的损失值之间的差异。没有这个特征的模型等价于如果这个特征从数据集中被排除在训练中的模型。由于在没有其中一个特征的情况下重新训练模型的计算成本很高,因此该模型是近似地使用原始模型构建的,该模型从集成中的所有树中删除了该特征。此特征重要性的计算需要数据集,因此,计算值取决于数据集。

计算原理

取决于达到最佳度量值的条件,以确保特征越重要,相应的重要性值就越高。

  • 最小/最大最佳价值指标

  • 确切的最佳价值指标

402 Payment Required

一般来说,LossFunctionChange 的值可以是负数。

变量说明:
  • 是指没有第个特征时数学期望值。如果第个特征在叶子的路径上,新的叶子值设置为具有不同路径的叶子值按特征值加权平均值。权重表示相应叶子中对象的总权重。如果没有为数据集指定权重,则此权重等于每个叶子中的对象数。
    对于特征组合,叶子上的平均值计算如下:

  • 是具有数据集公式值的向量。如果提供了训练和验证数据集,则使用训练数据集的值。

  • metric 是训练参数中指定的损失函数。

用于计算的池随机子集大小确定如下:

特点
  • 比预测值变化更准确

  • 比 Shap Values 更快

  • 假设可以总结几个特征的损失函数变化

基于Shap Values

基本上这个选项与前一个选项类似,因为它还计算了移除一个特征后损失函数的变化。但不同的是,每次特征移除后都会重新计算分数(损失函数变化)。

计算原理

ShapValues 方法为每个对象 计算长度为 的向量 (其中 是特征数量)。该向量的每个元素表示相应特征对对象 的预测值的贡献。因此,如果我们将向量的值相加,我们就会得到这个对象的预测。

鉴于我们模型的这种表示,我们可以轻松计算没有特定特征的损失函数值。

—— 对象的损失
—— 没有特征 的 对象的损失

基于形状值的特征消除包含以下步骤:

  1. 从空的消除特征集 开始

  2. 计算当前损失值

    402 Payment Required

  3. 对于每个可用的特征,使用 shap 值计算分数作为损失函数的变化:

    402 Payment Required

  4. 消除一个得分最低的特征并将其添加到集合。

  5. 如果仍然需要消除特征,则返回步骤 2。

特点
  • 最准确

  • 相对较慢

特征选择用法

CatBoost 通过 CatBoost 模型的 select_features 方法提供特征选择算法。一个简单的用法示例:

model = CatBoost(params)
summary = model.select_features(
    train_pool,              # 用于训练的池
    eval_set,                # 用于提前停止和特征分数的池
    features_for_select,     # 允许消除哪些特征?
    num_features_to_select,  # 你要选择多少特征?
    algorithm,               # 基于 PredictionValuesChange、LossFunctionChange 或 ShapValues
    steps,                   # 允许训练模型多少次?
                             # 更多步骤 - 更准确的选择,尤其是对于 PredictionValuesChange
    shap_calc_type,          # Approximate、Regular 或 Exact 之一
                             # 用于 LossFunctionChange 和 ShapValues 算法
    train_final_model,       # 是否需要用选定的特征拟合模型?
    plot                     # 用度量值构建一个美丽的图?
)

print('Selected features indices:', summary['selected_features'])
print('Selected features names:', summary['selected_features_names'])
print('Eliminated features indices:', summary['eliminated_features'])
print('Eliminated features names:', summary['eliminated_features_names'])

特征选择应用

我们将在回归数据集中的 20 个信息特征和 80 个冗余特征上综合比较不同算法,看看这些算法如何选择信息特征。

from catboost import Pool
import numpy as np
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
# 创建包含 100 个特征中的 20 个信息特征的综合数据集
X, y, coef = make_regression(
    n_samples=1000,
    n_features=100,
    n_informative=20,
    random_state=0,
    coef=True
)
important_features = np.argwhere(coef > 0).flatten()
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.25, random_state=0)
train_pool = Pool(train_X, train_y)
test_pool = Pool(test_X, test_y)
print('Feature\t\tImportance')
print(np.array([important_features, coef[important_features]]).T)
Feature		Importance
[[ 1.          1.47727962]
 [13.         85.97273915]
 [16.         19.89836739]
 [19.         22.75125982]
 [27.         54.72802752]
  ...
 [85.         37.24269761]
 [87.         22.96530155]
 [92.         10.2855638 ]
 [94.         78.99714576]
 [96.         86.80129038]]

定义函数模板

from catboost import CatBoostRegressor, EShapCalcType, EFeaturesSelectionAlgorithm

def select_features_syntetic(algorithm: EFeaturesSelectionAlgorithm, steps: int = 1):
    print('Algorithm:', algorithm)
    model = CatBoostRegressor(iterations=1000, random_seed=0)
    summary = model.select_features(
        train_pool,
        eval_set=test_pool,
        features_for_select=list(range(X.shape[1])),     # 选择所有的特征
        num_features_to_select=len(important_features),  # 我们想要选择最重要的特征
        steps=steps,                                     # 更多的步骤-更准确的选择
        algorithm=algorithm,
        shap_calc_type=EShapCalcType.Regular,            # 可以是Approximate, Regular and Exact
        train_final_model=True,                          # 用选定的特征训练模型
        logging_level='Silent',
        plot=True
    )
    print('Selected important features: {}/{}'.format(
        len(set(important_features).intersection(summary['selected_features'])),
        len(important_features)
    ))
    print('Not selected important features:', set(important_features).difference(summary['selected_features']))
    return summary

基于ShapValues的RFE选择特征

synthetic_shap_summary = select_features_syntetic(
      algorithm=EFeaturesSelectionAlgorithm.RecursiveByShapValues)
Algorithm: EFeaturesSelectionAlgorithm.
RecursiveByShapValues

6a5e7211cc393b9419669c1a5c1bbe8e.gif

b5957cd88a1ce81d912555bff28ff31e.png
Selected important features: 19/20
Not selected important features: {1}

我们可以看到只有一个重要的特征被淘汰了,它是所有重要特征中系数最低的特征。

基于LossFunctionChange的RFE选择特征

synthetic_lfc_summary = select_features_syntetic(
    algorithm=EFeaturesSelectionAlgorithm.RecursiveByLossFunctionChange)
Algorithm: EFeaturesSelectionAlgorithm.RecursiveByLossFunctionChange

783c6bac50e8c9027a12a93794a99b3d.gif

6c47715e3221581d3fed5eb8eb65e8d9.png
Selected important features: 19/20
Not selected important features: {1}

在这里我们还可以看到,只有一个最不重要的特征被消除了。但是最终模型损失值存在差异(悬停在绘图的右侧红色方块上)。当基于 LossFunctionChange 的方法给出 𝑅𝑀𝑆𝐸=59.7642 时,基于 ShapValues 的方法给出 𝑅𝑀𝑆𝐸=58.9742。我们看看哪些特征被 SHAP 方法选中,哪些特征被 LFC 方法淘汰。

print(
    'Features selected by SHAP method and eliminated by LFC method:',
    set(synthetic_shap_summary['selected_features']).difference(synthetic_lfc_summary['selected_features'])
)
print(
    'Features selected by LFC method and eliminated by SHAP method:',
    set(synthetic_lfc_summary['selected_features']).difference(synthetic_shap_summary['selected_features'])
)

基于PredictionValuesChanges的RFE选择特征

synthetic_pvc_summary = select_features_syntetic(
    algorithm=EFeaturesSelectionAlgorithm.RecursiveByPredictionValuesChange)
Algorithm: EFeaturesSelectionAlgorithm.
RecursiveByPredictionValuesChange

f2bcf1c99ed22b49d0ebe453d03f7b99.gif

5b2535cdb40499d76bb0e8d3fc65ffda.png
Selected important features: 15/20
Not selected important features: 
{1, 92, 49, 55, 61}

我们可以在这里看到两件事:

  1. 基于 PredictionValuesChange 的方法仅选择了 20 个重要特征中的 15 个。

  2. 没有绘制中间点——这是因为我们基于预测值变化的这些点的近似值是没有意义的。

7 steps

所有方法的准确性,尤其是基于 PredictionValuesChange 的方法,可以通过更多的steps来提高。接下来我们尝试增加steps。

synthetic_pvc_summary_7_steps = select_features_syntetic(
    algorithm=EFeaturesSelectionAlgorithm.RecursiveByPredictionValuesChange,
    steps=7
)
Algorithm: EFeaturesSelectionAlgorithm.RecursiveByPredictionValuesChange

deac7db061af8780a5e36c3dfafcd89e.gif

71d51182e9f0d4af5c9f034bfefaf6b3.png
Selected important features: 18/20
Not selected important features: {1, 61}

7 个步骤使我们能够从 20 个重要特征中选择 18 个。虽然这比其他算法的结果要少,但得到了更好的最终损失值 58.909 。

推荐阅读:

我的2022届互联网校招分享

我的2021总结

浅谈算法岗和开发岗的区别

互联网校招研发薪资汇总
2022届互联网求职现状,金9银10快变成铜9铁10!!

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)
发送【1222】获取一份不错的leetcode刷题笔记

发送【AI四大名著】获取四本经典AI电子书
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值