我常想,如果我重新开始学习,那么在入门机器学习之前,我希望自己先了解哪些信息?本文旨在以一种速览、直白的方式,向有意入门的新手分享一下我对机器学习的浅见。
常见的机器学习问题包括分类,聚类,回归,关联规则等。其中分类算法是最广泛使用,而二分类又是其中最常见的。一封邮件是否是垃圾邮件(正常邮件/垃圾邮件),一个病灶是否是良性(良性/恶性),一个用户是否会违约(违约/不违约),一张图片是否人脸肖像(人脸/非人脸),手写数字的机器识别(0~9的多分类),这些问题都在分类的范畴。
常见的分类算法有逻辑回归、决策树、随机森林、提升树等。在说到具体的算法使用之前,需要先明确几个关于机器学习的概念。
目标函数,顾名思义,就是模型优化的目标。
目标函数 = 损失函数 + 正则化项
模型优化的目标有两个:一是使得预测值和真实值之间的差距最小化,二是使得模型不要过于复杂(因为复杂的模型不够健壮,或者说容易过拟合,导致在真实环境中表现不佳)。损失函数用来衡量预测值与真实值之间的差距,正则化项用来控制模型的复杂度。所谓正则化,即为“规则化”,含义就是使用规则约束模型的复杂度。
综上,目标函数的目标,就是在一定约束条件下(即正则化)的损失函数最小化。或者用更直白的话说,就是在模型不要过于复杂的前提下,使得预测值和真实值之间的差距最小。
常用的目标函数有哪些呢?譬如平方损失函数,交叉熵函数等,通常这些不需要我们深究,算法会自动选择合适的函数。
因变量就是模型预测的值(或称y值,标签值,只有一个),自变量就是模型使用的值(或称x值,特征值,理论上可以是任意多个)。训练集是用来训练模型的数据集,测试集/验证集是用来测试模型有效性的数据集,经验上两者通常保持7:3左右的比重,但这个没有一定之规。跨期验证是一种特殊的验证集,意思是模型使用较老的数据进行训练,使用较新的数据进行验证,以验证模型随着时间推移是否仍然有效。
交叉验证,通常指K折交叉验证,是指将数据集按某种抽样方法分成K份,使得每一份都至少经过一次训练和测试。通常在数据较少时使用。
正例(或称1)、反例(或称0)指的是二分类的因变量。通常我们考察的值,称之为正例。譬如我们想找到一批用户中的违约用户,那么违约用户就是正例,未违约用户就是反例。但这个叫法没有一定之规,反着叫也无关大局。
过拟合指模型为了适应训练数据而变得过于复杂,导致在测试集上表现较差;欠拟合则相反,因模型过于简单而导致表现较差。
过拟合是机器学习中最常见的问题之一,围绕这个问题有着各种或简单、或高阶的解决方式。为什么过拟合这么常见呢?如果说传统的编程是给出一系列规则,让机器照着规则去执行任务并得出结果,那么机器学习就是反过来的:它首先得到一系列结果(训练集),然后尝试从结果中发现规则。当机器进行训练时,如果不加以限制,往往会对数据中无关的信息做出过度的反应。例如,机器会发现根据用户的姓名来判断他是不是违约,准确率很高,但这没有任何实践意义,因为姓名只是一个人的代号,没有提供任何信息。把这样的模型运用到测试集中,会发现效果很差。这就是过拟合。
参数指模型训练完成后,产生的一系列对应着各个特征的系数。某些情况下,这些参数是静态的,可以直接套用在公式上(如逻辑回归)或写在代码里,这种情形称之为“可解释”;某些情况下则没有静态的参数(如xgboost),称之为“不可解释”,或者“黑箱”。
超参数是指在模型训练之前,你必须先定义好的一系列参数,比如缺失值的处理方式等。调参是训练模型中重要的一环,一般会反复进行,因为如果有多个超参数,那么它们之间的组合数量是比较可观的,需要一定的经验。
如何评价一个模型好不好呢?简单来说就是看它在测试集上的表现。
怎么评价它在测试集上的表现?
比较直观的有准确率、精确率等。但受数据分布的影响,它们可能意义不大。比如一个数据集中有10个恶性肿瘤,9990个良性肿瘤,如果模型全部判断为良性肿瘤,那么准确率达到99.9%,但结果并没有任何意义。因此要配合其他一些指标如召回率、误判率等等。
更常用的指标是ROC曲线,AUC值,KS曲线/KS值,提升度,混淆矩阵等。
这些指标难以直观地解释,我尽量说的直白一些。
ROC曲线(就不说中文名了,只会让你困惑)衡量的是,当我想召回更多的正例时,需要容忍多少的反例被错误地召回(它的纵横坐标分别是召回率和误判率。召回率,所有正例中有多少被正确地召回;误判率,所有负例中有多少被误判为正例。)最好情况是,不需要容忍任何错误,即可召回全部的正例;最坏情况是,当我想召回一定比例的正例,必须召回同等比例的反例,相当于随机选择。
AUC值是ROC曲线下的面积。AUC在0.5~1之间,越接近1,表示模型越好;越接近0.5,表示模型的判断越接近随机值。为什么不可以小于0.5呢?因为如果小于0.5,模型就是反向指标,只需要将模型结果反转一下(正变反,反变正),就是一个更好的模型,AUC值就大于0.5。
KS值(也不说中文名了,是两位数学家名字的首字母)用来衡量模型区分两种类别(二分类)的能力。具体来说,想象两条曲线(KS曲线),一条代表累计的划分正确的正例比例(“真正率”,或召回率),一条代表累计的“错误地划分为正例”的反例比例(“假正率”,或误判率),两条曲线之间最大的距离就是KS值。KS值在0~1之间,越接近1,代表模型的区分度越好。通常>0.2表示有区分度,越高越好。
从本质上说,ROC曲线、KS曲线都是相通的,这里就不展开了。
混淆矩阵是一个2*2的矩阵,分别表示预测正实际正、预测正实际负、预测负实际正、预测负实际负的案例数量。混淆矩阵可以直观地看到模型判断的效果如何。
说到混淆矩阵,必须穿插着讲一下阈(yu)值的概念。
如果模型输出的是概率值,那么需要定一个阈值才能够使用,混淆矩阵才能被算出。如果一个模型训练的不错,AUC很高,那么一个合适的阈值能够发挥模型的最大威力。通常来说这并不是难点,但是也需要注意。有人说最佳阈值是最大的KS值对应的概率值,但这个实际上跟你的业务偏好密切相关,更多的是一个经验值,而没有一致标准的最佳。
提升度,或称lift,表示一个模型对正例的捕捉能力高于随机选择的倍数。譬如1000个案例中有100个违约用户,如果一个模型预测的头部20%数据(也就是200条)中捕捉到了50%的违约用户(50个),那么对应的提升度就是(50/200)/(100/1000) = 2.5。提升度=1,意味着模型的选择和随机选择没有区别。
免费的有R语言、Python,收费的有SAS、SPM等。
R语言和Python都是机器学习语言中的佼佼者,令人欣慰的是,它们相对于其他编程语言,也非常容易入门。其中关键在于,它们有着成熟的开源社区,来自全世界的优秀的开发者贡献了他们的高度封装的代码,使得使用者仅需要加载相关的“包/模块”,即可使用机器学习算法,而无需了解其中的算法细节,真正做到了一行代码顶一百行。
当然它们也有缺点。最主要的一点是,它们的运行效率都不高,对于计算量大、实时性高的作业,需要做优化。常用的优化方式是,用C语言修改其中承担密集计算任务的部分。关于它们训练的模型如何部署到线上环境,后面还会涉及。
收费工具的优点是有着良好的售后支持。SAS是老牌的建模工具,历史悠久,名气大,价格贵,几乎所有银行都用它。SPM是它的竞争者,主打Treenet算法,擅长处理极多变量、高度缺失的数据。它们都是高度集成的工具,不需要写代码(当然也可以写),只需要点击鼠标即可实现复杂的功能和运算。相对而言,它们的部署上线也有成熟的傻瓜式的做法。
另外还有其他一些常见工具,如SPSS、Matlab等,笔者接触不多,就不展开了。
如前所述,分类算法常见的如:逻辑回归,决策树类算法,随机森林,提升树类算法,支持向量机(SVM)等。下面择要进行介绍。
逻辑回归是最经典最悠久的分类算法。虽然它的名字有回归二字,但它并不是回归算法,而是分类算法。它的分类效果中规中矩;最大的优点是解释性好,可以直接生成参数,套用公式。它对缺失值敏感,需要对缺失值进行预处理(填充或删除)。
决策树类算法是分类算法中一个庞大的家族,常见的有CART树(中文名:分类与回归树,也就是既可以做分类,也可以做回归),C50,ID3等。决策树算法的共性是,它们都通过生成节点、生成树干、生成叶片、剪枝的方式进行工作。具体而言,它们首先通过某种方式找到重要性最高的变量,在此节点进行分裂,使得分裂后的两部分纯度最高,再找到次重要的变量,依次循环作业,直到到达目标或预定深度。
不同决策树算法的区别在于它们如何判断变量的重要性。具体而言,CART树可以使用“信息增益”或“基尼系数”来判断,C50使用“信息增益率”,ID3使用“信息增益”,还有一些决策树算法根据卡方P值等进行判别。这些名词这里不做展开,简而言之,基尼系数用来衡量分类的纯度(纯度指的就是某一类别的比重。显然,分类的纯度越高越好。);信息增益用来衡量给定一个条件后不确定性减少的程度;信息增益率与信息增益相似,不同的是它对取值较多的变量进行了惩罚。决策树的优点是对缺失值通常不敏感,解释性强,可视化好,缺点是容易过拟合。
随机森林,顾名思义,实际上就是一堆决策树,它们通过投票表决的方式得出预测结论,因此能够比较好地克服决策树容易过拟合的问题。随机森林本质上是一颗颗CART树,所以它也支持回归和分类。随机森林是一个广受欢迎的算法,应用场景广泛,基本无需调参,简单可靠。
提升树类算法包括adaboost、xgboost等。adaboost效率较低,笔者接触不多,这里就xgboost做一下简介。
上文提到SPM主打Treenet算法,又名GBDT,中文名梯度提升决策树,这是一个强大的算法,而xgboost(极限梯度提升树)是它的优化版。相对于GBDT,xgboost在优化时对损失函数进行了二阶泰勒展开(不必纠结于术语),信息损失更少。xgboost本质上也是若干棵CART树,通过对每棵树分类的结果按权重进行加总,得到最终的预测结果。
xgboost是一个极为强大的算法,尤其当数据质量较差时(如缺失值多、无关变量多、字符型变量多),它相对于其他算法的优势会逐渐体现出来。同时由于用到了多线程,它的运行效率也很高。在各项国际建模赛事中,xgboost屡屡帮助参赛者夺魁。
虽然它有这么多优点,但缺点也很明显:首先它是一个黑箱,无法进行定量解释;其次它的建模过程涉及到较多超参数,调参的工作量比较大。其中比较重要的参数有:目标函数的选择(逻辑回归、多分类),正则化的强度(>=1的数值),学习速率(<1的正值,用以控制模型学习的步长,控制该速率可以使后续的迭代有更大的学习空间,相对的训练时间也更长),模型评价指标(如AUC、错误率等),以及一系列控制树形态、优化样本分布不均衡问题的参数,等等。
简单小结一下应用场景:
随机森林、CART树、逻辑回归,支持离散和连续型的因变量,其中CART树对缺失值不敏感。那么由CART树组成的随机森林为什么对缺失值敏感呢?笔者也不清楚。欢迎赐教。
C50、adaboost 仅支持离散型因变量。
对于二分类,xgboost 仅支持连续型因变量(且必须为0、1值),对缺失值不敏感。
缺失值:
缺失值是最常见的数据质量问题。缺失值的处理有很多方式,这里提纲挈领地介绍一下。
简单粗暴法:直接插入0值或均值;不处理,使用对缺失值不敏感的算法。
删除行列法:删除包含过多缺失值的行或列。
估测法:使用相关的其他自变量对缺失值进行估测。
专业法:各个工具有专业的包或功能模块来处理缺失值,只是用起来比较麻烦和耗时。
组合法:以上方法的组合。
通常来说,你可以先尝试一下简单粗暴法,如果效果不如人意,再做更专业的处理。
正负样本分布不均衡:
通常,如果负样本数量比正样本高1~2个数量级,这种程度的不均衡不需要做特殊处理。
但是如果正样本数量极少,远远少于负样本,这种情况下训练的结果往往会失真。针对这种情况,也有成熟的解决方案,其核心都是消除样本不均衡的问题。这里简要提其中一个:下采样。
所谓下采样,就是将正例单独分成一份,负例随机均分成K份,每一份负样本都与正样本组合训练一次,形成K个模型,再通过K个模型投票表决,得出最终的预测结论。
1)明确训练目标:以始为终,首先明确目标。是分类问题,聚类问题,回归问题?需要得出概率还是二值结果?
2)读取数据:方式有很多,可以读取csv等平面文件,也可以连接数据库。
3)数据预处理:删除不相关变量、明显有错误的记录等。
4)特征工程:缺失值处理;归一化;降维;分箱;构造新变量等。
补充说明:
所谓归一化,就是考虑到不同变量取值的数量级差异较大,导致模型模型收敛速度变慢,因此事先将各变量放大或缩小至同一量纲。常见的有线性归一化、0均值标准化方法。归一化只对收敛速度有影响,对模型的好坏没有影响。
所谓降维,就是从原始的特征中抽取最重要的信息,组合成新的较少的特征。这样做的好处,一是减少了训练的计算量,二是防止过拟合。常用的降维方法有PCA(主成分分析)等。
所谓分箱,就是将连续变量离散化。比如,将年龄划分为幼年,青年,中年,老年等。这样做通常会使模型更加健壮,不容易过拟合。那么如何评价分箱的效果的好坏呢?对应的指标叫做IV(信息价值,取值0~1),和基尼系数类似,它通过加权汇总每个分箱内部的纯度,来评价分箱效果的好坏。纯度越高,IV越大。例如上述年龄的分箱是最好的方式吗?只有IV能告诉你,IV越大越好。
根据数据质量的不同,特征工程可能花费很多时间,也可能不需要任何处理。
5)训练、测试数据的划分:除了随机划分以外,如果作业涉及到时间维度,还需要加入跨期验证。
6)选择算法-建立模型-调参-验证结果-优化算法:通过调参优化模型,如果还是不满意,可能需要回到上一步重做特征工程。
7)结果保存/部署上线:如果是离线的预测任务,需要将结果保存,通常到这里就结束了;但如果是实时的生产任务,则还需要部署模型。
如果是逻辑回归模型,那么可以直接用模型的系数构造公式,将变量代入,即可得到对应的概率值。这种最简单直观。但逻辑回归本身的表现通常不是最好的。
如果是决策树,则可以通过Java代码对树的各个节点进行构造,也很方便。
如果是其他解释性差、或者黑箱中的模型,则无法这样做。这时候分两种情况:
1)你使用的是SPM这样的收费工具,它可以将模型直接转化成Java代码。
2)你使用的是R/Python之类的工具。这时候你必须亲自动手了。比较简单的方法是,在模型环境(如R)中,构造一个函数,它接收一系列自变量作为参数,返回预测结果的值。然后在Java环境中,建立与R的连接( rConnection),通过API调用这个模型函数。这里需要注意的是,在生产环境中,调用之后,连接不要关闭。如果关闭,那么系统会回收模型的内存,则每次调用都会重新建立连接、重新训练模型。
以上只是浮光掠影地看一眼机器学习知识的概况,其中的任何一个知识点都足以写一篇完整的论文来讲述。作者笔力不足,在此不做深入探讨。写的不到位处,欢迎质疑。接下来(下一篇文章)我们会以一个真实的案例来做练习。