/ ML

机器学习系列 -- 如何处理任意ML问题

原作者:
Abhishek Thakur
Senior Data Scientist @ Searchmetrics Inc.

一名数据科学家每天都要处理海量的数据,有的数据科学家表示每天60%-70%的时间都花在了清洗,鼓捣(误,原文为munging),和将数据准备上ML模型的餐桌,这篇博文主要关注的是第二个部分,i.e.应用机器学习模型(包括预处理的阶段)。本文里介绍的流程来自于作者上百场ML竞赛的经验,这些经验虽然非常的宽泛但也十分有用(其他的更复杂的方法是存在的)。

在这里,我们会使用Python来完成一系列任务。

处理数据

在应用ML模型之前,数据必须被转换成表格形式,这段过程往往是最耗时和困难的,如下图所示:

表格数据是机器学习或数据挖掘中最常见的数据呈现形式。这里我们得到了一张表,每一行有不同的数据样本x,和对应的标签y。标签依据问题的种类可以是单列也可以是多列,我们将以X表示data,以Y表示标签。

标签的种类

标签给问题一个明确的定义

  • 单列,二进制值(分类问题)
  • 单列,实值(回归问题,预测单一值)
  • 多列,二进制值(分类问题,有两个以上的类)
  • 多列,实值(回归问题,多个值的预测)
  • 多标签(分类问题,一个样本可以属于多个类型)

评估指标

对任意类型的ML问题,我们必须知道如何设定评估指标,例如,在数据分布不均的二分类问题中我们通常选择ROC曲线下方的面积。在多标签或多分类问题中,我们通常选择范畴明确的cross-entropy或者multi-class log loss和均方差指标,以免出现回归不稳定。
由于组合指标的方法很多,我不会极其详尽的阐述不同的评估指标。

Python库

让我们安装最基本和最重要的python库:numpy和scipy.

我不用Anaconda的原因是我喜欢有更多的自由空间。

机器学习框架

在2015年的时候,我发明了一套用于自动机器学习的框架,它现在仍在开发(很快会推出),本文中我们也以这套框架为例,如下图:

图:AUTOCOMPLETE,为机器学习而生的框架,ICML2015

在上面的框架中,粉色的线条代表了最常被经过的路径。在我们精炼数据为一张表之后,我们可以开始建立ML模型了。

第一步是鉴明问题是什么,这可以由观看标签来得到。我们必须知道一个问题是二分类法,多分类或者多标签分类或者回归问题。这之后,我们将数据分成两个不同的部分,训练集和验证集。

图:在分类问题中,数据的分拆必须严格按照标签,使用分层抽样


如果遇到回归问题,一个简单的K折拆分就足够了,不过一些复杂的分拆法倾向于保持标签的分布对于训练集和验证集相同,读者可以自行验证。

在这里我选择了eval_size(验证集的大小)为总数据集的10%。
在分拆数据集之后,我们不去动验证集,任何训练集上应用的操作必须同样在验证集上重放。而验证集必须不能和训练集join到一起。这么做会产生一个结果非常好但是实际上高度过拟合的模型,这是毫无用处的。

下一步是鉴别数据中不同的变量。这里通常我们要对付三种变量:数值型变量、分类型变量、字符串型变量。让我们用经典的Titanic数据集进行说明:


在这里survival是一个标签,在上一步中我们已经将标签从训练集中分离了出来,接下来,我们还有pclass,sex,embarked.这些变量具有不同的级别,我们把它们列为分类变量。诸如age,sibsp,parch等我是数值型变量。Name是一个字符串型变量(不过我不认为这个变量有助于判断生存率。。)

首先分离出数值型变量。这些变量通常不需要任何处理,那么我们可以开始在这些之上应用数据规范化和机器学习模型。

有两种方法处理分类型数据:

  • 将类型数据转化为标签

  • 将标签转化为二进制变量(one-hot编码)

记住先用LabelEncoder将类型转化为数字,再在数字之上使用OneHotEncoder。

Titanic数据集没有太好的字符串变量例子,我们试着给出一条通用的处理文本变量的规则,我们可以整合所有的文本变量到一个变量,然后使用某些算法将其转化为数字。

比如文本数据可以这样join:
Alt Text
那么我们可以在这之上使用CountVectorizer或者TfidfVectorizer
Alt Text
或者
Alt Text
TfidfVectorizer一般都表现的比CountVectorizer好,如下是我觉得有奇效的一组参数:

如果你只在训练集上应用这些向量化函数,记得将他们导出到硬盘,以供后面在验证集上用。
Alt Text
下一步,我们来到stacker模块,stacker模块不是模块的stacker,而是feature的stacker.用以上的处理步骤处理后得出的不同特征可以使用stacker模块将这些特征合并起来。
Alt Text
你可以用numpy的hstack或sparse hstack者水平的将所有特征堆叠起来,取决于你的特征密集还是稀疏。
Alt Text
特征的堆叠也可以借助Feature Union模块,以免有时候还有另外的处理步骤比如pca或者特征选择(我们会在晚些时候提到Decomposition(解构)和特征选择。

一旦我们将特征堆叠起来,我们可以开始应用机器学习模型了。在这个阶段你需要接触的模型应该是Ensemble tree based models.包括:

  • RandomForestClassifier
  • RandomForestRegressor
  • ExtraTreesClassfier
  • ExtraTreesRegressor
  • XGBClassifier
  • XGBRegressor
    我们不能对没有规范化的特征应用线性模型,要使用线性模型,我们需要先用Scikit-learn中的Normalizer或StandardScaler

这些规范化方法只在稠密的特征情况下有用,对于稀疏的矩阵,我们可以使用with_mean=false参数的StandardScaler.

如果上述步骤给出了一个良好的模型,那我们可以开始对Hyperparameters进行优化,如果上述步骤给出的模型仍然欠优,我们可以采取下述方法继续改进它:
下述步骤包含了分解的方法:

为了简单起见,我们会抛开LDA和QDA变换不谈。对于高维数据,一般地,PCA被用来分解数据。对于图片,从10-15个分解组件开始,慢慢增加,直到结果的质量显著增加。对于其他类型的数据,我们一般在起始选择50-60个组件(只要我们能一直处理数值型数据,我们就倾向于避免使用PCA)。
Alt Text
对于文本型数据,在将其转化为稀疏矩阵之后,最好采用奇异值分解(SVD,Singular Value Decomposition).scikit-learn中能找到奇异值分解的一种变种:TruncatedSVD

能使得TF-IDF(词频-文档逆频)方法有用的SVD分解组件数目通常为100-200.大于这个数目的话计算性能和资源消耗之比会变得不经济。

在对模型进行了这些性能评估后,为了更好的评估线性模型,我们可以开始进行数据的缩放。规范化的或缩放后的特征则可以被送往ML模型或特征选择模块。

有多种方式可以选择特征,一种最常见的方式就是贪婪特征选择(往前的或往后的).在贪婪选择中我们先选择一个特征来训练模型,以一个固定的指标来评估模型的性能,接着我们一个一个的增加/移除特征,并记录每一次增加/减少后模型的性能。最后我们选择带来最好性能的一批特征。

一种使用AUC的贪婪特征选择算法实现
注意这个实现并不完美,大家因地制宜。

其他更快的特征选择方法包括从模型中选择最好的特征,我们可以例如去关注logit(分类评定模型)的系数或者我们可以训练一个随机森林来选择最好的特征以备后用。

记住保持estimator的数量在低水平,不对Hyperparameters做过多的优化,以免出现过拟合。

特征选择还可以通过梯度助推机(Gradient Boosting Machines)达成。不过用scikit-learn提供的xgboost可能会比GBM更快和更具扩展性。

我们还可以对稀疏的数据集使用RandomForestClassfier/RandomForestRegressor/xgboost进行特征选择。

另外一个流行的对Positive稀疏数据集做特征选择的方法是基于chi-2的特征选择,这在scikit-learn里也有

在这里,我们在使用chi2的同时一并使用了SelectKBest,来从数据中选择出了20个特征。这同样也成为了我们需要优化的一个Hyperparameter。

别忘了DUMP你每一步中用过的转换器,你会需要在验证集上再次用到它们。

下一个关键的步骤,是模型的选择+Hyperparameter优化:
Alt Text
在选择一个机器学习模型的时候,我们通常会用到下述算法:

Classfication
  • 随机森林
  • 梯度助推机
  • 逻辑回归
  • 纯真贝叶斯
  • 支撑向量机
  • k近邻
Regression

让我们讲这些Hyperparameters分解出来:

RS* = 不能确定合适的值,推荐在这些Hyperparameters里使用Random Search.

在我的看法中,上述模型性能上已经完爆其他模型,因此我们在这里不需要继续评估其他模型了。
记得导出转换器。。。

然后单独将这些转换器应用到验证集上:

上述规则和框架在大多数的数据集上都表现的非常出色,当然它们曾经在面对非常复杂的数据集时候出现问题,没有什么是完美的,只有不断的学习不断的改进才是正解。