kaggle竞赛技巧(其二)——利用null importance筛选有效特征

permutation的问题在于计算量随着特征的增加而线性增加,对于维度很高的数据基本上难以使用。下面介绍一下kaggle 大佬 oliver 发明的 null importance 特征重要性计算方法。

xgboost特征重要性计算算法的问题

  1. 树模型自带的特征重要性评估可能偏向于具有高基数的类别特征或连续特征。这是因为,这些特征在决策树分裂时,因为其多样的分割点,往往能带来更显著的不纯度降低(如基尼不纯度或MSE减少量)。特别是在使用LightGBM和XGBoost这类模型时,哪怕有非常重要的离散特征,模型仍然会倾向于增加连续型特征/高基数特征的分裂次数,导致重要特征无法体现。

  2. 对于xgb和lgb等这类拟合能力超强的模型来说,很多和标签完全无关的特征甚至是随机加入的噪声,都能通过海量的子树与标签建立密切的联系,即只要子树的量够多,哪怕是随机噪声和标签之间都能建立映射。而且在数据集中加入噪声作为特征后,直接输出xgboost给出的特征重要性排序,噪声很有可能是优于正常的特征的,如果我们根据xgboost自身的特征重要性排序来删除特征,则会删除掉很多潜在的有用的信息。

为什么不能用permutation?

之前的文章介绍过permutation,其是处理噪声问题的一种方法,但是该方法的最大问题在于:其计算量与特征维度正成比,面对高维数据计算过慢,而在进行kaggle比赛时,所使用的特征通常定然在千维以上。而null importance则可以较好的解决这样的问题。

null importance的核心思想

Null Importance的核心思想是:一个较好的特征与标签必然具有较高的关联程度,因此,如果将标签随机打乱,好的特征的特征重要性必然出现大幅度的下滑,而差的特征,或者说与标签无关的特征的特征重要性则不会有太大的改变。因此计算两种特征重要性,一种是实际的特征重要性,另一种是打乱标签训练得到的null importance,然后使用后者对前者做一个修正,以得到真实的特征重要性。

如果感觉这段有点难于理解,可以先看具体算法步骤。

具体算法步骤

  1. 计算基准特征重要性

    • 首先,训练一个标准的树模型,以此模型输出的特征重要度作为基准(实际重要性)。
  2. 生成Null Importance分布

    • 打乱数据的标签,破坏特征与标签之间的实际关联。
    • 使用与步骤一同样相同的方法重新训练模型,输出特征重要度,称为Null Importance。这代表了模型在不考虑真实标签关联时对特征的随机评价。
    • 由于标签被打乱,导致每次计算的Null Importance可能会有很大的波动,因此需要多次重复上述过程,建立Null Importance的分布,以更准确的评估特征重要性。
  3. 评估特征分数

    • 对于有用的特征,其实际重要性远高于Null Importance。
    • 对于无用或者不那么重要的特征,其Null Importance很可能接近甚至超过实际重要性。
    • 结合步骤1和步骤2的结果,我们可以通过比较实际重要性和Null Importance来评分每个特征。这种比较可以用多种方法实现,例如差值、比值等。 oliver 使用的评分公式是实际重要性与Null Importance分布的75%分位数的对数比值。
  4. 特征选择与决策

    • 根据计算出的特征分数,我们可以设定一个阈值,以决定保留哪些特征。
    • 还可以通过观察实际重要性与Null Importance之间的差异,来做出关于特征选择的更直观的决定。

对于第三步:特征分数的计算,oliver给出的衡量方案核心逻辑对应的代码如下

python 复制代码
feature_scores = []
for _f in actual_imp_df['feature'].unique():
    f_null_imps_gain = null_imp_df.loc[null_imp_df['feature'] == _f, 'importance_gain'].values
    f_act_imps_gain = actual_imp_df.loc[actual_imp_df['feature'] == _f, 'importance_gain'].mean()
    gain_score = np.log(1e-10 + f_act_imps_gain / (1 + np.percentile(f_null_imps_gain, 75)))  # Avoid didvide by zero
    f_null_imps_split = null_imp_df.loc[null_imp_df['feature'] == _f, 'importance_split'].values
    f_act_imps_split = actual_imp_df.loc[actual_imp_df['feature'] == _f, 'importance_split'].mean()
    split_score = np.log(1e-10 + f_act_imps_split / (1 + np.percentile(f_null_imps_split, 75)))  # Avoid didvide by zero
    feature_scores.append((_f, split_score, gain_score))

scores_df = pd.DataFrame(feature_scores, columns=['feature', 'split_score', 'gain_score'])
scores_df = scores_df.sort_values('split_score', ascending=False)

其使用了计算出的null importance的75%分位数与真实重要性的比值,而后取对数,即:

gain_score = np.log(1e-10 + f_act_imps_gain / (1 + np.percentile(f_null_imps_gain, 75)))

笔者在公司的算法赛中使用了null importance 进行了特征重要性筛选,将1600维度压到了500多维,发现线上F1是有少量提升的。

相关推荐
前端小巷子1 小时前
Vue 3 运行机制
前端·vue.js·面试
再学一点就睡9 小时前
实现大文件上传全流程详解(补偿版本)
前端·javascript·面试
泽虞13 小时前
《LINUX系统编程》笔记p3
linux·运维·服务器·c语言·笔记·面试
围巾哥萧尘17 小时前
「电脑的故事」从电脑的故事谈用人的策略🧣
面试
学历真的很重要17 小时前
Eino 开源框架全景解析 - 以“大模型应用的搭积木指南”方式理解(一)
后端·语言模型·面试·golang·ai编程·eino
UrbanJazzerati17 小时前
Salesforce Flow 中集合操作的常见误解:值拷贝 vs. 引用传递
面试
丘山子18 小时前
分享链接格式不统一,rel="share-url" 提案试图解决这个问题
前端·面试·html
uhakadotcom19 小时前
最近rust生态有啥能力更新?
后端·面试·github
PAK向日葵20 小时前
【算法导论】MT 0823笔试题题解
算法·面试
折果21 小时前
如何在vue项目中封装自己的全局message组件?一步教会你!
前端·面试