读者朋友们,你们好,我是Abhay Pawar,平时热衷于参加一些机器学习的比赛,不知道你以前有没有听过kaggle比赛,如果你参加过就会知道这个比赛是非常有趣的,而且很容易让人上瘾。这几年,我开发了一套标准流程来探索特征变量,以便建立更好的机器学习模型。正是这些简单而强大的技巧让我在Instacart Market Basket Analysis 比赛中获得了前2%的名次,不单单在竞赛中,我在Kaggle之外也经常使用到它们,接下来就开始我的分享吧!
基于数值型数据去建立监督学习模型的一个最重要的方面,就是要很好地理解这些特征。查看模型的局部依赖关系图,如下图所示,有助于理解模型的输出如何随特征的变化而变化。
但是,这些图存在的问题是,它们是使用经过训练的模型创建的,如果我们可以直接从训练数据创建这些图,就可以帮助我们更好地理解底层数据。事实上,它是可以帮助你做以下工作的:
为了便于使用,我打算使用python中的featexp包实现它,同时将介绍如何将其用于特征探索,我们将利用Kaggle上的Home Credit Default Risk竞赛中的数据集作为例子,该竞赛的任务是根据数据预测信用违约者。
如果因变量(目标变量)是二分类变量,散点图是没有意义的,因为所有点都位于0或1上,而对于连续性目标变量,太多的数据点也会使得我们很难理解目标随特征变化的趋势。而Featexp创建了合适的图来解决这个问题。接下来就让我们试试看!
from featexp import get_univariate_plots # Plots drawn for all features if nothing is passed in feature_list parameter. get_univariate_plots(data=data_train, target_col='target', features_list=['DAYS_BIRTH'], bins=10)
Featexp将数值型特征变量进行分箱后作为X轴,然后计算每个分箱中目标变量的均值,以将其绘制在上面左侧的图中。在此例中,目标变量的均值表示违约率。由图可知,DAYS_BIRTH负值越大(年龄越大)的客户违约率越低。这是有道理的,因为年轻人通常更有可能违约。这些图有助于我们了解该特性对客户的描述以及它将如何影响模型。右边的图表显示了每个分箱中的顾客数量。
噪声会导致过度拟合,然而识别它们并非易事。在featexp中,你可以通过一个测试集,并比较训练集和测试集的特征趋势,以识别噪声。这个测试集并不是实际的测试集,而是已知目标变量结果的测试集或验证集(建模时通常先将数据划分为训练集和测试集)。
get_univariate_plots(data=data_train, target_col='target', data_test=data_test, features_list=['DAYS_EMPLOYED'])
Featexp计算了两个指标,并将其通过图形展示,以助于检测噪声:
以下特征没有保持相同的趋势,因此趋势相关性较低,为85%。这两个指标都可用于去除噪声特征。
当有很多特征并且它们彼此相关时,减少趋势相关性较低的特征效果就会很好,它会减少过拟合,并且能避免其它相关特征的信息丢失。同样重要的是,不要删除太多重要的特征,因为这可能会导致模型性能下降。此外,你不能使用特征重要性来识别这些有噪声的特征,因为它们可能相当重要,但同时也会存在噪声!
使用不同时间段的测试数据会使得效果更好,因为这样你就可以确保特征趋势是否随着时间的推移而保持不变。
featexp中的get_trend_stats()函数会为每个特征返回一个带有趋势相关性和变化的数据。
from featexp import get_trend_stats stats = get_trend_stats(data=data_train, target_col='target', data_test=data_test)
让我们尝试在数据中减少低相关性的特征,看看结果会如何变化:
我们可以看到,用于筛选特征的趋势相关阈值越高,提交到Leaderboard(LB)上的AUC就越高,而保留这些重要特征则会将LB AUC提高到0.74,同样有趣的是,本地测试的AUC变化并没有比LB AUC大,为确保你的验证策略正确,使本地测试集的AUC与LB AUC变化一致也很重要,完整的代码可以在featexp _ demo中找到。
通过观察图表,有助于创建更好的特征,更好地理解数据就能探索更好的特征工程。但是,除此之外,它还可以帮助我们改进现有的特征,让我们看看EXT_SOURCE_1的另一个特性:
EXT_SOURCE_1值越高的客户,违约率越低,但是,第一个分箱(8%的违约率)没有跟随特征趋势(先上升后下降),它只有-99.985左右的负值,而且人口众多。这可能意味着这些是特殊值,因此不遵循特征趋势,幸好,非线性模型学习这种关系不会有问题。但是,对于逻辑回归这样的线性模型,这种特殊的值和空值(将显示为单独的分箱)应该用具有相似违约率的值来计算,而不是简单地用特征均值来计算。
Featexp还可以帮助你评估特征的重要性。DAYS_BIRTH和EXT_SOURCE_1都有很好的趋势。但是,EXT_SOURCE_1的人口集中在一个特殊的组中,这意味着特征对大多数客户具有相同的信息,因此不能很好地区分它们,这说明它可能没有DAYS_BIRTH那么重要,根据XGBoost模型的特性重要性也表明,DAYS_BIRTH实际上比EXT_SOURCE_1更重要。
观察Featexp的绘图,还有助于在复杂的特征工程代码中帮你找出bug,你只需做两件事即可:
遗漏检测和理解
下面的特征在“Nulls”分箱中违约率是0%,在其他分箱违约率是100%,显然,这是数据遗漏的极端情况。只要当客户违约,特征才会有一个数值。产生这种情况的原因可能是bug的存在,或者该特征实际上是只针对违约者进行的特征计算(在这种情况下应该删除它)。了解特征遗漏的问题所在,就可以加快调试速度。
由于featexp计算两个数据集之间的趋势相关性,因此可以很容易地用于模型监控,每次重新训练模型时,新的训练数据都可以与经过良好测试的训练数据(通常是你第一次构建模型时的训练数据)进行比较。趋势相关性可以帮助您监控特征及其与目标变量的关系是否发生变化。
通过这些简单的技巧让我在现实生活和Kaggle上构建更好的模型,仅仅需要15分钟,就可以利用Featexp创建并查看这些图表,但这绝对是值得的,因为在这之后你就不会无从下手了。