如何用机器学习处理二元分类任务?

640?wx_fmt=jpeg

图像是猫还是狗?情感是正还是负?贷还是不贷?这些问题,该如何使用合适的机器学习模型来解决呢?

问题

暑假后,又有一批研究生要开题了。这几天陆续收到他们发来的研究计划大纲。

其中好几个,打算使用机器学习做分类。

但是,从他们的文字描述来看,不少人对机器学习进行分类的方法,还是一知半解

考虑到之前分享机器学习处理分类问题的文章,往往针对具体的任务案例。似乎对分类问题的整体步骤与注意事项,还没有详细论述过。于是我决定写这篇文章,帮他们梳理一下。

他们和你一样,也是我专栏的读者。

如果你对机器学习感兴趣,并且实际遇到了分类任务,那我解答他们遇到的一些疑问,可能对于你同样有用。

所以,我把这篇文章也分享给你。希望能有一些帮助。

监督

监督式机器学习任务很常见。主要模型,是分类与回归。

就分类问题而言,二元分类是典型应用。

例如决策辅助,你利用结构化数据,判定可否贷款给某个客户;

例如情感分析,你需要通过一段文字,来区分情感的正负极性;

例如图像识别,你得识别出图片是猫,还是狗。

今天咱们就先介绍一下,二元分类,这个最为简单和常见的机器学习应用场景。

注意要做分类,你首先得有合适的数据。

什么是合适的数据呢?

这得回到我们对机器学习的大类划分。

分类任务,属于监督式学习。

监督式学习的特点,是要有标记。

例如给你1000张猫的图片,1000张狗的图片,扔在一起,没有打标记。这样你是做不了分类的。

虽然你可以让机器学习不同图片的特征,让它把图片区分开。

但是这叫做聚类,属于非监督学习

天知道,机器是根据什么特征把图片分开的。

你想得到的结果,是猫放在一类,狗放在另一类。

但是机器抓取特征的时候,也许更喜欢按照颜色区分。

结果白猫白狗放在了一个类别,黄猫黄狗放在了另一个类别。跟你想要的结果大相径庭。

如果你对非监督学习感兴趣,可以参考《如何用Python从海量文本抽取主题?》一文。

所以,要做分类,就必须有标记才行。

但是标记不是天上掉下来的。

大部分情况下,都是人打上去的。

标记

打标记(Labeling),是个专业化而繁复的劳动。

你可以自己打,可以找人帮忙,也可以利用众包的力量。

例如亚马逊的“土耳其机器人”(Amazon Mechanical Turk)项目。

640?wx_fmt=jpeg

别被名字唬住,这不是什么人工智能项目,而是普通人可以利用业余时间赚外快的机会。

你可以帮别人做任务拿佣金。任务中很重要的一部分,就是人工分类,打标记。

640?wx_fmt=png

因此如果你有原始数据,但是没有标记,就可以把数据扔上去。

说明需求,花钱找人帮你标记。

类似的服务,国内也有很多。

建议找知名度比较高的平台来做,这样标记的质量会比较靠谱。

如果你还是在校学生,可能会觉得这样的服务价格太贵,个人难以负担。

没关系。假如你的研究是有基金资助项目的一部分,可以正大光明地找导师申请数据采集费用。

但若你的研究属于个人行为,就得另想办法了。

不少学生选择的办法,是依靠团队支持。

例如找低年级的研究生帮忙标记。

人家帮了忙,让你发表了论文,顺利毕业。你总得请大家吃一顿好吃的,是吧?

学习

有了标记以后,你就能够实施监督学习,做分类了。

这里我们顺带说一下,什么叫做“机器学习”。

这个名字很时髦。

其实它做的事情,叫做“基于统计的信息表征”。

先说信息表征(representation)。

你的输入,可能是结构化的数据,例如某个人的各项生理指标;可能是非结构化数据,例如文本、声音甚至是图像,但是最终机器学习模型看到的东西,都是一系列的数字。

这些数字,以某种形式排布。

可能是零维的,叫做标量(scalar);

可能是一维的,叫做向量(vector);

可能是二维的,叫做矩阵(Matrice);

可能是高维的,叫做张量(Tensor)。

640?wx_fmt=jpeg

但是,不论输入的数据,究竟有多少维度,如果你的目标是做二元分类,那么经过一个或简单、或复杂的模型,最后的输出,一定是个标量数字。

你的模型,会设置一个阈值。例如0.5。

640?wx_fmt=png

超出这个数字的,被分类到一处。

反之,被分类到另一处。

任务完成。

那么模型究竟在做什么呢?

它的任务,就是把输入的数据,表征成最终的这个标量。

打个不恰当的比方,就如同高考

每一个考生,其实都是独特的。

每个人都有自己的家庭,自己的梦想,自己的经历,自己的故事。

但是高考这个模型,不可能完整准确表征上述全部细节。

它简单地以考生们的试卷答题纸作为输入,以一个最终的总成绩作为输出。

然后,划定一个叫做录取分数线的东西,作为阈值(判定标准)。

达到或超出了,录取。

否则,不录取。

这个分数,就是高考模型对每个考生的信息表征

所谓分类模型的优劣,其实就是看模型是否真的达到了预期的分类效果。

什么是好的分类效果?

大学想招收的人,录取了(True Positive, TP);

大学不想招收的人,没被录取(True Negative, TN)。

什么是不好的分类效果?

大学想招收的人,没能被录取(False Negative, FN);

大学不想招收的人,被录取了(False Positive, FP)。

640?wx_fmt=png


好的模型,需要尽力增大 TP 和 TN 的比例,降低 FN 和 FP 的比例。

评判的标准,视你的类别数据平衡而定。

数据平衡,例如1000张猫照片,1000张狗照片,可以使用 ROC AUC。

640?wx_fmt=png

数据不平衡,例如有1000张猫的照片,却只有100张狗的照片,可以使用 Precision 和 Recall ,或者二者相结合的 F1 score。

因为有这样明确的评估标准,所以二元分类模型不能满足于“分了类”,而需要向着“更好的分类结果”前进。

办法就是利用统计结果,不断改进模型的表征方法。

所以,模型的参数需要不断迭代。

恢复高考后的40年,高考的形式、科目、分值、大纲……包括加分政策等,一直都在变化。这也可以看作是一种模型的迭代。

“表征”+“统计”+“迭代”,这基本上就是所谓的“学习”。

结构化

看到这里,希望你的头脑里已经有了机器学习做二元分类问题的技术路线概貌。

下面咱们针对不同的数据类型,说说具体的操作形式和注意事项。

先说最简单的结构化数据。

例如《贷还是不贷:如何用Python和机器学习帮你决策?》一文中,我们见到过的客户信息。

640?wx_fmt=png

处理这样的数据,你首先需要关注数据的规模。

如果数据量大,你可以使用复杂的模型。

如果数据量小,你就得使用简单的模型。

为什么呢?

因为越复杂的模型,表征的信息就越多。

表征的信息多,未必是好事。

因为你抓住的,既有可能是信号,也有可能是噪声。

如果表征信息多,可是学习过的数据不多,它可能就会对不该记住的信息,形成记忆。

在机器学习领域,这是最恐怖的结果——过拟合(overfitting)。

翻译成人话,就是见过的数据,分类效果极好;没见过的数据,表现很糟糕。

640?wx_fmt=png

举一个我自己的例子。

我上学前班后没多久,我妈就被请了家长。

因为我汉语拼音默写,得了0分。

老师嘴上说,是怀疑我不认真完成功课;心里想的,八成是这孩子智商余额不足。

其实我挺努力的。

每天老师让回家默写的内容,都默了。

但是我默写的时候,是严格按照“a o e i u ……”的顺序默的。

因为每天都这样默写,所以我记住的东西,不是每个读音对应的符号,而是它们出现的顺序。

结果上课的时候,老师是这样念的“a b c d e ……”

我毫无悬念没跟下来。

我的悲剧,源于自己的心智模型,实际上只反复学习了一条数据“a o e i u ……”。每天重复,导致过拟合,符号出现在顺序中,才能辨识和记忆。

因此,见到了新的组合方式,就无能为力了。

看,过拟合很糟糕吧。

确定了模型的复杂度以后,你依然需要根据特征多少,选择合适的分类模型。

640?wx_fmt=png

上图来自于 Scikit-learn ,我截取了其中“分类”模型部分,你可以做参考。

注意模型的效果,实际上是有等级划分的。

例如根据 Kaggle 数据科学竞赛多年的实践结果来看,Gradient Boosting Machine 优于随机森林,随机森林优于决策树。

这么比有些不厚道,因为三者的出现,也是有时间顺序的。

让爷爷跟孙子一起赛跑,公平性有待商榷。

因此,你不宜在论文中,将不同的分类模型,分别调包跑一遍,然后来个横向对比大测评

许多情况下,这是没有意义的。

虽然显得工作量很大。

但假如你发现在你自己的数据集上面,决策树的效果就是明显优于 Gradient Boosting Machine ,那你倒是很有必要通过论文做出汇报。

尽管大部分审稿人都会认为,一定是你算错了

另一个需要注意的事项,是特征工程(feature engineering)。

什么叫特征工程呢?

就是手动挑选特征,或者对特征(组合)进行转化。

例如《如何用Python和深度神经网络锁定即将流失的客户?》一文中,我们就对特征进行了甄别。其中三列数据,我们直接剔除掉了:

  • RowNumber:行号,这个肯定没用,删除

  • CustomerID:用户编号,这个是顺序发放的,删除

  • Surname:用户姓名,对流失没有影响,删除

正式学习之前,你需要把手头掌握的全部数据分成3类:

  • 训练集

  • 验证集

  • 测试集

我在给期刊审稿的时候,发现许多使用机器学习模型的作者,无论中外,都似乎不能精确理解这些集合的用途。

训练集让你的模型学习,如何利用当前的超参数(例如神经网络的层数、每一层的神经元个数等)组合,尽可能把表征拟合标记结果。

就像那个笑话说的一样:

Machine Learning in a Nutshell:

Interviewer: what's you biggest strength?

Me: I'm a quick learner.

Interviewer: What's 11*11?

Me: 65.

Interviewer: Not even close. It's 121.

Me: It's 121.

而验证集的存在,就是为了让你对比不同的超参数选择,哪一组更适合当前任务。它必须用训练集没有用过的数据。

验证集帮你选择了合适的超参数后,它的历史任务也就结束了。

这时候,你可以把训练集、验证集合并在一起,用最终确定的超参数组合进行训练,获得最优模型。

这个模型表现怎么样?

你当然需要其他的数据来评判。这就是为什么你还要划分出另外的测试集。

图像

François Chollet 在自己的书中举过一个例子,我觉得很有启发,一并分享给你。

假如你看到了这样的原始数据:

640?wx_fmt=jpeg

你该怎么做分类?

有的同学一看是图像,立刻决定,上卷积神经网络

别忙,想想看,真的需要“直接上大锤”吗?

别的不说,那一圈的刻度,就对我们的模型毫无意义。

你可以利用特征工程,将其表达为这样的坐标点:

640?wx_fmt=jpeg

你看,这样处理之后,你立刻就拥有了结构化数据。

注意这个转换过程,并不需要人工完成,完全可以自动化。

但是举一反三的你,估计已经想到了“更好的”解决方案:

640?wx_fmt=png


对,这样一来,表达钟表时间的数据,就从原先的4个数字,变成了只需要2个。

一个本来需要用复杂模型解决的问题,就是因为简单的特征工程转化,复杂度和难度显著下降。

其实,曾经人们进行图片分类,全都得用特征工程的方法。

那个时候,图片分类问题极其繁琐、成本很高,而且效果还不理想。

手动提取的特征,也往往不具备良好的可扩展性和可迁移性。

于是,深度卷积神经网络就登场了。

如果你的图片数据量足够多的话,你就可以采用“端到端”的学习方式。

所谓“端到端”,是指不进行任何的特征工程,构造一个规模合适的神经网络模型,扔图片进去就可以了。

但是,现实往往是残酷的。

你最需要了解的,是图片不够多的时候,怎么办。

这时候,很容易出现过拟合。

因为深度神经网络,属于典型的复杂模型。

640?wx_fmt=png

这个时候,可以尝试以下几个不同的方法:

首先,如果有可能,搜集更多的带标注图片。这是最简单的办法,如果成本可以接受,你应该优先采用。

其次,使用数据增强(Data Augmentation)。名字听起来很强大,其实无非是把原始的数据进行镜像、剪裁、旋转、扭曲等处理。这样“新的”图片与老图片的标注肯定还是一样的。但是图片内容发生的变化,可以有效防止模型记住过多噪声。

640?wx_fmt=png

第三,使用迁移学习。

所谓迁移学习,就是利用别人训练好的模型,保留其中从输入开始的大多数层次(冻结保留其层次数量、神经元数量等网络结构,以及权重数值),只把最后的几层敲掉,换上自己的几层神经网络,对小规模数据做训练。

640?wx_fmt=jpeg

上图同样来自于 François Chollet 的著作。

这种做法,用时少,成本低,效果还特别好。如果重新训练,图片数少,就很容易过拟合。但是用了迁移学习,过拟合的可能性就大大降低。

其原理其实很容易理解。

卷积神经网络的层次,越是靠近输入位置,表达的特征就越是细节;越到后面,就越宏观。

640?wx_fmt=jpeg

识别猫和狗,要从形状边缘开始;识别哆啦a梦和瓦力,也一样要从形状边缘开始。因此模型的底层,可以被拿来使用。

你训练的,只是最后几层表征方式。结构简单,当然也就不需要这么多数据了。

第四,引入 Dropout, Regularization 和 Early Stopping 等常规方法。注意这些方法不仅适用于图像数据。

640?wx_fmt=png

以 Dropout 为例。假如一个模型因为复杂,所以记住了很多噪声,那么训练的时候,每次都随机将一定比例的神经元“扔掉”(设置权重为0),那么模型的复杂度降低。而且因为随机,又比降低层数与神经元个数的固化模型适用性更高。

文本

前面说过了,机器不认得文本,只认得数字。

所以,要对文本做二元分类,你需要把文本转换成为数字。

这个过程,叫做向量化。

向量化的方式,有好几种。大致上可以分成两类:

第一类,是无意义转换。也就是转换的数字,只是个编号而已,本身并不携带其他语义信息。

这一类问题,我们在《如何用Python和机器学习训练中文文本情感分类模型?》中,已经非常详细地介绍过了。

你需要做的,包括分词(如果是中文)、向量化、去除停用词,然后丢进一个分类模型(例如朴素贝叶斯,或者神经网络),直接获取结果,加以评估。

但是,这个过程,显然有大量的语义和顺序信息被丢弃了。

第二类,是有意义转换。这时候,每个语言单元(例如单词)转换出来的数字,往往是个高维向量。

640?wx_fmt=png

这个向量,你可以自己通过训练来产生。

但是这种训练,需要对海量语料进行建模。

建模的过程,成本很高,占用庞大存储空间,运算量极大。

因此更常见的做法,是使用别人通过大规模语料训练后的结果。也就是我们曾经介绍过的词嵌入预训练模型。

具体内容,请参见《如何用Python处理自然语言?(Spacy与Word Embedding)》和《如何用 Python 和 gensim 调用中文词嵌入预训练模型?》。

注意如果你有多个预训练模型可以选择,那么尽量选择与你要解决任务的文本更为接近的那种。

毕竟预训练模型来自于统计结果。两种差别很大的语料,词语在上下文中的含义也会有显著差异,导致语义的刻画不够准确。

如果你需要在分类的过程中,同时考虑语义和语言单元顺序等信息,那么你可以这样做:

第一步,利用词嵌入预训练模型,把你的输入语句转化为张量,这解决了词语的语义问题;

第二步,采用一维卷积神经网络(Conv1D)模型,或者循环神经网络模型(例如 LSTM),构造分类器。

注意这一步中,虽然两种不同的神经网络结构,都可以应用。但是一般而言,处理二元分类问题,前者(卷积神经网络)表现更好。

640?wx_fmt=png

因为卷积神经网络实际上已经充分考虑了词语的顺序问题;而循环神经网络用在此处,有些“大炮轰蚊子”。很容易发生过拟合,导致模型效果下降。

实施

如果你了解二元分类问题的整体流程,并且做好了模型的选择,那么实际的机器学习过程,是很简单的。

对于大部分的普通机器学习问题,你都可以用 Scikit-learn 来调用模型。

注意其实每一个模型,都有参数设置的需要。但是对于很多问题来说,默认初始参数,就能带来很不错的运行结果。

640?wx_fmt=jpeg

Scikit-learn 虽好,可惜一直不能很好支持深度学习任务。

因而不论是图像还是文本分类问题,你都需要挑选一个好用的深度学习框架。

注意,目前主流的深度学习框架,很难说有好坏之分。

640?wx_fmt=png

毕竟,在深度学习领域如此动荡激烈的竞争环境中,“坏”框架(例如功能不完善、性能低下)会很快被淘汰出局。

然而,从易用性上来说,框架之间确实有很大区别。

易用到了一种极致,便是苹果的 Turi Create 。

从《如何用Python和深度神经网络识别图像?》和《如何用Python和深度神经网络寻找近似图片?》这两篇文章中,你应该有体会,Turi Create 在图像识别和相似度查询问题上,已经易用到你自己都不知道究竟发生了什么,任务就解决了。

但是,如果你需要对于神经网络的结构进行深度设置,那么 Turi Create 就显得不大够用了。

毕竟,其开发的目标,是给苹果移动设备开发者赋能,让他们更好地使用深度学习技术。

640?wx_fmt=png

对于更通用的科研和实践深度学习任务,我推荐你用 Keras 。

它已经可以把 Theano, Tensorflow 和 CNTK 作为后端。

对比上面那张深度学习框架全家福,你应该看到,Keras 覆盖了 Google 和 微软自家框架,几乎占领了深度学习框架界的半壁江山。

照这势头发展下去,一统江湖也说不定哦。

为什么 Keras 那么厉害?

因为简单易学。

简单易学到,显著拉低了深度学习的门槛。

就连 Tensorflow 的主力开发人员 Josh Gordon,也已经认为你根本没必要去学习曾经的 Tensorflow 繁复语法了。

640?wx_fmt=jpeg

直接学 Keras ,用它完成任务,结束。

另外,使用深度学习,你可能需要 GPU 硬件设备的支持。这东西比较贵。建议你采用租用的方式。

《如何用云端 GPU 为你的 Python 深度学习加速?》提到的 FloydHub,租赁一个小时,大概需要1美元左右。注册账号就赠送你2个小时;

640?wx_fmt=png


至于《如何免费云端运行Python深度学习框架?》中提到的 Google Colab ,就更慷慨了——到目前为止,一直是免费试用。

喜欢请点赞。还可以微信关注和置顶我的公众号“玉树芝兰”(nkwangshuyi)。

如果你对数据科学感兴趣,不妨阅读我的系列教程索引贴《如何高效入门数据科学?》,里面还有更多的有趣问题及解法。

答疑社区在这里:

640?wx_fmt=jpeg


  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值