模型训练优化

113 阅读13分钟

模型训练

开发步骤

  1. 数据采集和标记

    在数据采集阶段,需要收集尽量多的特征。特征越全,数据越多,训练出来的模型才会越准确。

    数据标记到有监督的学习方法是必须的。

  2. 数据清洗

    数据清洗包括单位统一、去掉重复的数据及噪声数据、让数据具备结构化特征,以方便作为机器学习算法的输入。

  3. 特征选择

    特征选择的方法之一是人工选择方法,即对逐个特征进行人员分析,然后选择合适的特征集合。

    另外一个方法是通过模型来自动完成,如PCA算法 。

  4. 模型选择

    选择哪个模型,和问题领域、数据量大小、训练时长、模型的准确度等多方面有关。

  5. 模型训练和测试

    数据集分成训练数据集和测试数据集。以确保测试的准确性,即模型的准确性是要用它“没见过”的数据来测试,而不能用那些用来训练这个模型的数据来测试。

    更合理的数据集划分方案是分成3个,此外还要再加一个交叉验证数据集。

  6. 模型性能评估和优化

    训练时长

    数据集是否足够多

    模型的准确性

    模型是否能满足应用场景的性能要求

  7. 模型使用

    训练出来的模型可以把参数保存起来,下次使用时直接加载即可。一般来讲,模型训练需要的计算量是很大的,也需要较长的时间来训练,这是因为一个好的模型参数,需要对大型数据集进行训练后才能得到。而真正使用模型时,其计算量是比较少的,一般是直接把新样本作为输入,然后调用模型即可得出预测结果。

模型优化

为什么要进行特征选择?

  • 降低复杂度:随着特征数量的增加,很多数据挖掘算法需要更多的时间和资源。减少特征数量,是提高算法运行速度,减少资源使用的好方法。
  • 降低噪音:增加额外特征并不总会提升算法的表现。额外特征可能扰乱算法的正常工作,这些额外特征间的相关性和模式没有实际应用价值(这种情况在小数据集上很常见)。只选择合适的特征有助于减少出现没有实际意义的相关性的几率。
  • 增加模型可读性:根据成千上万个特征创建的模型来解答一个问题,对计算机来说很容易,但模型对我们自己来说就晦涩无比。因此,使用更少的特征,创建我们自己可以理解的模型,就很有必要。

特征优化

  • 使用tf-idf
  • 特征量增加--增加其他特征
  • 去掉出现频率低的特征(CountVectorizer可以设置)
  • 二分类比较好的八十,差不多的七十

性能优化

过拟合可以采取的措施:

  • 获取更多的训练数据
  • 减小输入的特征数量
  • 欠拟合说明模型太简单了,需要增加模型的复杂度:
  • 增加有价值的特征
  • 增加多项式特征

模型融合

模型融合:模型融合就是训练多个模型,然后按照一定的方法集成过个模型,应为它容易理解、实现也简单,同时效果也很好,在工业界的很多应用,在天池、kaggle比赛中也经常拿来做模型集成。

模型融合技术的两种方法: Bagging Boosting

bagging、boosting的对比

Bagging主要在优化variance(即模型的鲁棒性)

boosting主要在优化bias(即模型的精确性)

bagging:Boostrap Aggregating 意思是重采样 然后在每个样本上训练出来的模型取平均值

Boosting:是迭代算法,每一次迭代都根据上一次迭代的预测结果对样本进行加权

variance是模型的鲁棒性,即模型的泛化能力,如果训练的样本高度相关,那么模型的鲁棒性肯定不会好。

bagging:通过重采样的方法,各个模型之间的相关性并不高,所以可以降低variance,而并没有针对bias进行优化。而Bagging是通过重采样的方法降低了模型的过拟合的可能性。

Boosting:从优化的角度看,每次都根据上一次迭代的结果进行优化,所以各个子模型之间是高度相关的,variance并不会显著提高,所以,Boosting主要是针对bias进行优化。同时,Boosting是将许多弱分类器放在一起,组合成一个强分类器,而所谓的弱分类器,就是bias大的分类器,而强分类器就是bias小的分类器,所以bias是boosting的主要优化目标。

样本不均衡问题

一、样本的过采样和欠采样。
  1. 过采样:将稀有类别的样本进行复制,通过增加此稀有类样本的数量来平衡数据集。该方法适用于数据量较小的情况。
  2. 欠抽样:从丰富类别的样本中随机选取和稀有类别相同数目的样本,通过减少丰富类的样本量来平衡数据集。该方法适用于数据量较大的情况。
  3. 也可以将过采样和欠采样结合在一起使用。
  4. 使用SMOTE方法来构造样本。

  SMOTE算法是一种过采样的算法。这个算法不是简单的复制已有的数据,而是在原有数据基础上,通过算法

产生新生数据。

  算法思想:基于距离度量的方式计算两个或多个稀有类样本之间的相似性。

       然后选择其中的一个样本作为基础样本,

       再在邻居样本中随机选取一定数量的样本对那个基础样本的一个属性进行噪声。每次处理一个属

性,通过这样的方式产生新生数据。

二、使用多个分类器进行分类。

  方法一中介绍的过采样,欠采样,都存在相应的问题。

   过采样:可能会存在过拟合问题。(可以使用SMOTE算法,增加随机的噪声的方式来改善这个问题)

  欠采样:可能会存在信息减少的问题。因为只是利用了一部分数据,所以模型只是学习到了一部分模型。

  有以下两种方法可以解决欠采样所带来的问题。

  方法一:模型融合 (bagging的思想 )

   思路:从丰富类样本中随机的选取(有放回的选取)和稀有类等量样本的数据。和稀有类样本组合成新的

训练集。这样我们就产生了多个训练集,并且是互相独立的,然后训练得到多个分类器。

     若是分类问题,就把多个分类器投票的结果(少数服从多数)作为分类结果。

     若是回归问题,就将均值作为最后结果。

  方法二:增量模型 (boosting的思想)

   思路:使用全部的样本作为训练集,得到分类器L1

     从L1正确分类的样本中和错误分类的样本中各抽取50%的数据,即循环的一边采样一个。此时训练样

本是平衡的。训练得到的分类器作为L2.

     从L1和L2分类结果中,选取结果不一致的样本作为训练集得到分类器L3.

     最后投票L1,L2,L3结果得到最后的分类结果。

三、将二分类问题转换成其他问题。

  可以将不平衡的二分类问题转换成异常点检测,或者一分类问题(可使用one-class svm建模)

四、改变正负类别样本在模型中的权重。

  使用代价函数学习得到每个类的权值,大类的权值小,小类的权值大。刚开始,可以设置每个类别的权值与样

本个数比例的倒数,然后可以使用过采样进行调优。

五、注意点:

  1.不平衡问题的评价指标

   准确度这个评价指标在类别不均衡的分类任务中并不能work。几个比传统的准确度更有效的评价指标:

   混淆矩阵(Confusion Matrix):使用一个表格对分类器所预测的类别与其真实的类别的样本统计,分别

为:TP、FN、FP与TN。

   精确度(Precision)

   召回率(Recall)

   F1得分(F1 Score):精确度与找召回率的加权平均。

   特别是:

   Kappa (Cohen kappa)

  ROC曲线(ROC Curves):见Assessing and Comparing Classifier Performance with ROC Curves

  2.交叉验证

   在K-Fold 校验中,每一份数据集中原则上应该保持类别样本比例一样或者近似,如果每份数据集中小类

样本数目过少,那么应该降低K的值,知道小类样本的个数足够。

性能指标

评估一个二分类的分类器的性能指标有:准确率、查准率(precision)、查全率(recall)、F1值以及ROC和AUC等

查准率(Precision)和召回率

直观理解为: 在所有预测为正例中,真正正例的比例。(有点绕,多读几遍就好)

模型准确性并不能评价一个算法的好坏。因此引入另外两个概念,精确率(Precision,P)和召回率(Recall,R)。具体定义如下:

以关注的类为正类,其他类为负类,分类器在测试集上的预测或正确或不正确,四种情况出现的总数分别记作:

TP——将正类预测为正类数

FN——将正类预测为负类数

FP——将负类预测为正类数

TN——将负类预测为负类数

准确率(Accuracy):模型预测正确数量所占总量的比例

准确率(Accuracy) = 正确预测数 / 预测总数

ACC=(TP+TN)/(TP+TN+FP+FN)

精确率定义为:预测为正类别中正确的量(在所有正类别样本中,被正确识别为正类别的比例)

P=TP/(TP+FP)

召回率定义为:本来就是正累的样本预测正确的量(在被识别为正类别的样本中,为正类别的比例)

P=TP/(TP+FN)

F1 Score

F1Score=2*PR/(P+R)

查全率(Recall)

直观理解为: 在所有真实的正例中,预测为正例的比例。

ROC

什么是ROC曲线

先有一个概念:很多学习器能输出一个实值或者概率预测,然后设定一个阈值,高于阈值为正类,反之负类。分类的过程就是设定阈值,并用阈值对预测值做截断的过程,当这个阈值发生变动时,预测结果和混淆矩阵就会发生变化,最终导致一些评价指标的值的变化

简单说:AUC值越大的分类器,正确率越高。

为什么使用ROC曲线

既然已经这么多评价标准,为什么还要使用ROC和AUC呢?因为ROC曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。

在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。

模型保存

保存和加载单模型

training = sqlContext.read…  # data: features, label
rf = RandomForestClassifier(numTrees=20)
model = rf.fit(training)
​
model.save("myModelPath")
sameModel = RandomForestClassificationModel.load("myModelPath")

保存和加载多管道模型

val cvModel = cv.fit(training)
cvModel.save("myCVModelPath")
val sameCVModel = CrossValidatorModel.load("myCVModelPath")

归一化和标准化的区别

归一化特点

对不同特征维度的伸缩变换的目的是使各个特征维度对目标函数的影响权重是一致的,即使得那些扁平分布的数据伸缩变换成类圆形。 这也就改变了原始数据的一个分布。

好处:

  1. 提高迭代求解的收敛速度
  2. 提高迭代求解的精度

标准化特点

对不同特征维度的伸缩变换的目的是使得不同度量之间的特征具有可比性。同时不改变原始数据的分布。

好处:

  1. 使得不同度量之间的特征具有可比性,对目标函数的影响体现在几何分布上,而不是数值上
  2. 不改变原始数据的分布。

在sklearn.preprocessing 介绍的标准化方式有:

  1. preprocessing.scale()、preprocessing.StandardScaler(),使数据集呈现标准正态分布,即mean = 0,且标准差std = 1。
  2. MinMaxScaler 、MaxAbsScaler,前者使数据集分布在[0,1],后者分布在[-1,1]。这种方式通常在(1) 特征的标准差较小 (2) 可以使稀疏数据集中的0值继续为0,这两种情况下使用。
  3. preprocessing.QuantileTransformer(),将数据映射到[0,1]之间均匀分布,会破坏原数据之间的相关特性。
  4. 归一化方式:preprocessing.normalize(),将样本缩放成单位向量,(1)需要使用二次方程,比如点积或者其他核方法计算样本对之间的相似性(2)常用于文本分类和内容聚类的向量空间模型的基础。

spark mllib 和sklearn比较

第一种是基于Spark MLlib来学习。好处是学到的东西用到生产环境可以无缝切换,但是坏处也很明显,Spark东西很多,在自己的单机上跑很吃内存,比较慢,而且MLlib的类库并不丰富,很多算法需要自己再去找类库。

第二种是基于scikit-learn为主的一系列python工具来学习,包括上面提到的numpy, scipy, pandas, MatplotLib等等。好处是类库多,API强大,可以让你专注于数据的分析,例子也多,学习起来不难。当然也有缺点,就是这一大堆的python库,要熟练的用起来需要一段时间。 个人比较推荐这种方法

如果是深度学习,选TensorFlow;如果不是,看数据规模大不大,大的话选Spark的MLlib,否则选scikit-learn。或者也可以从硬件角度上来说,用TensorFlow的一般有强力GPU(甚至TPU),用Spark MLlib的一般有集群,什么都没有的一般用scikit-learn。;-)

Spark中ml和mllib的主要区别和联系如下:

  • ml和mllib都是Spark中的机器学习库,目前常用的机器学习功能2个库都能满足需求。
  • spark官方推荐使用ml, 因为ml功能更全面更灵活,未来会主要支持ml,mllib很有可能会被废弃(据说可能是在spark3.0中deprecated)。
  • ml主要操作的是DataFrame, 而mllib操作的是RDD,也就是说二者面向的数据集不一样。
  • DataFrame和RDD什么关系?DataFrame是Dataset的子集,也就是Dataset[Row], 而DataSet是对RDD的封装,对SQL之类的操作做了很多优化。
  • 相比于mllib在RDD提供的基础操作,ml在DataFrame上的抽象级别更高,数据和操作耦合度更低。
  • ml中的操作可以使用pipeline, 跟sklearn一样,可以把很多操作(算法/特征提取/特征转换)以管道的形式串起来,然后让数据在这个管道中流动。大家可以脑补一下Linux管道在做任务组合时有多么方便。
  • ml中无论是什么模型,都提供了统一的算法操作接口,比如模型训练都是fit;不像mllib中不同模型会有各种各样的trainXXX。
  • mllib在spark2.0之后进入维护状态, 这个状态通常只修复BUG不增加新功能。