特征选择是指从最相关的特征中选择一个子集进行模型训练的过程。特征选择是非常有用的,原因在于:
简化模型解释
减轻过拟合
减少训练时间
减少内存消耗
特征选择算法
特征选择技术可以分为几组:
包装法 - 基于训练模型的权重/系数消除特征。
过滤法 - 基于一些统计数据以及特征与目标变量之间的相关性来消除特征(无需训练模型)。
嵌入法 - 在模型训练期间消除特征,例如,通过应用 L1 正则化。
CatBoost 实现了一种包装法——递归特征消除。该算法包含以下步骤:
获取具有所有特征的数据集 D。
使用数据集 D 训练模型。
从经过训练的模型中获取每个特征的分数。
消除数据集 D 中得分最差的几个特征。
如果需要,返回第 2 步(通常执行特定次数或在损失函数变得更好时)。
特征分数
CatBoost 如何计算特征的分数?这里我们一起学习几种选择。
基于预测值变化
对于每个特征,PredictionValuesChange 显示如果特征值发生变化,预测平均会发生多少变化。重要性值越大,平均而言,如果该特征发生变化,预测值的变化就越大。
计算原理
比较的叶子对在这些叶子路径上的节点中具有不同的分割值。如果满足分裂条件(这个条件取决于特征F),则对象进入左子树;否则它会转到右边的那个。
402 Payment Required
402 Payment Required
分别表示左右叶子中对象的总权重。如果没有为数据集指定权重,则此权重等于每个叶子中的对象数。
分别表示左右叶子中的公式值。
如果模型不是使用单个输入特征本身,而是使用特征的组合,则计算并输出这些特征的平均特征重要性。例如,该模型使用特征 f54
、c56
和 f77
的组合。首先,计算这些特征组合的特征重要性。然后将结果值除以3并分配给每个特征。
如果模型既单独使用一个特征又与其他特征组合使用,则该特征的总重要性值使用以下公式定义:
402 Payment Required
是第 j 个特征的个体特征重要性。402 Payment Required
是第 i 个组合特征中第 j 个特征的平均特征重要性。
特点
非常快
大的预测值变化并不总是意味着大的损失值变化
不适合排名损失函数
基于损失函数变化
每个输入特征的单独重要性值( 排名指标的默认特征重要性计算方法)。这种类型的特征重要性可用于任何模型,但对模型排名特别有用,因为其他特征重要性类型可能会产生误导性结果。
对于每个特征,该值表示具有该特征和没有该特征的模型的损失值之间的差异。没有这个特征的模型等价于如果这个特征从数据集中被排除在训练中的模型。由于在没有其中一个特征的情况下重新训练模型的计算成本很高,因此该模型是近似地使用原始模型构建的,该模型从集成中的所有树中删除了该特征。此特征重要性的计算需要数据集,因此,计算值取决于数据集。
计算原理
取决于达到最佳度量值的条件,以确保特征越重要,相应的重要性值就越高。
最小/最大最佳价值指标
确切的最佳价值指标
402 Payment Required
一般来说,LossFunctionChange 的值可以是负数。
变量说明:
是指没有第个特征时数学期望值。如果第个特征在叶子的路径上,新的叶子值设置为具有不同路径的叶子值按特征值加权平均值。权重表示相应叶子中对象的总权重。如果没有为数据集指定权重,则此权重等于每个叶子中的对象数。
对于特征组合,叶子上的平均值计算如下:是具有数据集公式值的向量。如果提供了训练和验证数据集,则使用训练数据集的值。
metric 是训练参数中指定的损失函数。
用于计算的池随机子集大小确定如下:
特点
比预测值变化更准确
比 Shap Values 更快
假设可以总结几个特征的损失函数变化
基于Shap Values
基本上这个选项与前一个选项类似,因为它还计算了移除一个特征后损失函数的变化。但不同的是,每次特征移除后都会重新计算分数(损失函数变化)。
计算原理
ShapValues 方法为每个对象 计算长度为 的向量 (其中 是特征数量)。该向量的每个元素表示相应特征对对象 的预测值的贡献。因此,如果我们将向量的值相加,我们就会得到这个对象的预测。
鉴于我们模型的这种表示,我们可以轻松计算没有特定特征的损失函数值。
—— 对象的损失
—— 没有特征 的 对象的损失
基于形状值的特征消除包含以下步骤:
从空的消除特征集 开始
计算当前损失值
402 Payment Required
对于每个可用的特征,使用 shap 值计算分数作为损失函数的变化:
402 Payment Required
消除一个得分最低的特征并将其添加到集合。
如果仍然需要消除特征,则返回步骤 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
Selected important features: 19/20
Not selected important features: {1}
我们可以看到只有一个重要的特征被淘汰了,它是所有重要特征中系数最低的特征。
基于LossFunctionChange的RFE选择特征
synthetic_lfc_summary = select_features_syntetic(
algorithm=EFeaturesSelectionAlgorithm.RecursiveByLossFunctionChange)
Algorithm: EFeaturesSelectionAlgorithm.RecursiveByLossFunctionChange
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
Selected important features: 15/20
Not selected important features:
{1, 92, 49, 55, 61}
我们可以在这里看到两件事:
基于 PredictionValuesChange 的方法仅选择了 20 个重要特征中的 15 个。
没有绘制中间点——这是因为我们基于预测值变化的这些点的近似值是没有意义的。
7 steps
所有方法的准确性,尤其是基于 PredictionValuesChange 的方法,可以通过更多的steps来提高。接下来我们尝试增加steps。
synthetic_pvc_summary_7_steps = select_features_syntetic(
algorithm=EFeaturesSelectionAlgorithm.RecursiveByPredictionValuesChange,
steps=7
)
Algorithm: EFeaturesSelectionAlgorithm.RecursiveByPredictionValuesChange
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电子书