2.3 数据挖掘与训练模型

我们在前面预览环节中,通过特征两两组合展示,以及主成分降维的方法,已经对数据有了初步的认识。但是这种认识,不等于明确的分类标准,真正用于实战中的模型,还是需要使用监督学习方法。接下来的内容,将介绍监督学习的一个基本流程。

2.3.1 第一步,准备数据

这一部分包括两部分的内容,一是将所有数据划分训练集、验证集与测试集,二是进行数据的标准化。

首先解释一些名词,即什么是训练集、验证集与测试集。如同前面提到的,监督学习就是一种唯分数论的应试教育,准确率越高越好,正如学生考试成绩越高越好一样。那么提高应试教育考试成绩的方法,同样也可以用在监督学习上,那就是题海战术。在题海战术的过程中,老师会拿一堆卷子给学生做,有的作为家庭作业,有的作为阶段性考试,如周考、月考等,最后留一些题目用在期末考试中,参见表2-3。

我们不妨把机器学习模型理解成做题的学生。平时学生做作业时是允许参考题目答案的,这也有助于学生理解解题思路;而有监督的机器学习模型在训练过程中,同样需要一份“题目”和“答案”,比如鸢尾花数据集中,150个样本就相当于150个考题,每个题目给出四个特征,要模型预测分类结果,参考答案这里也一并给出,让模型在训练阶段中不断地“对答案”,训练高分模型。

当然,这样做有一个问题,学生如果直接抄答案,作业会完成得又快又好,如何让这部分学生现行?考试,考试题不附有参考答案,抄作业的就现行了,所以老师会不断地进行小范围阶段性考试,检验学生的学习效果;有监督的机器学习也是一样,会使用验证集检验学生的学习效果,确认模型对于未知数据也有很好的表现。

最后,阶段测试考得再好,期末考试或者高考这样的大型考试没考好也没有用。这种大型考试不是给学生来学习的,而是用来排名比较的;机器学习最终的模型好不好,也需要看它在测试集上的表现,抛开其他一切因素,99.95%的准确率就是比99.94%的准确率要好。

表2-3 将机器学习模型理解为做题的学生

通常情况下,数据的所有者在拿到完整数据后会进行第一次划分,分出初步训练集以及测试集,将初步训练集的数据和结果以及测试集的数据交给数据科学家,然后自己留下测试集的分类结果,将用于评价不同数据科学家、不同模型提交的准确率。数据科学家拿到初步训练集后进行第二次划分,分出训练集以及验证集,用于训练模型以及对模型进行自我评价。

我们以题海战术为例,让大家更容易理解数据划分的目的,继而在收集数据、划分数据时要做到符合以下常识:

(1)题目和答案要有关系。同样,收集到的数据特征也必须和数据要预测的东西有关系。当然,这里并不要求所有数据都有关系,可以有冗余,也可以有干扰项。确认这一点的一种简单方法是,将这些数据给这个领域的人类专家,如果他可以对结果做出判断,那么机器就可以。

(2)合理划分作业和测试的比例。比如做单选题,如果只选ABCD后对答案,不思考背后的原因,可能做一份卷子和做一百份卷子没有什么区别,答案对多了还可能会得出“三长一短选最长”这种结论。同样,只做作业不考试,可能会在学习方法上产生方向性的错误。机器学习也一样,手里拿到一些数据之后,不妨将70%拿来作为训练集(家庭作业),30%拿来作为验证集(小测)。题海战术的题目,要尽量保证不同题型在作业和考试中一致,同样,不同种类的数据,在训练集验证集中的比例也应当保持一致。

(3)避免题目泄露。测试集中的数据不应出现在训练集和验证集中。

数据科学性除了需要合理进行数据集的划分之外,还需要对数据进行标准化操作。具体而言,就是很多样本通过减平均值、除标准差的方法将数据变成标准正态分布。这种做法的主要原因是,在训练数据的过程中,模型的参数会不断调整,而调整过程中,同样调整100,如果特征A的平均值是1,这个调整幅度就会显得过大,而对于平均值是10000的特征B而言,这个调整幅度就会显得过小,模型会浪费大量时间去适应不同特征的分布,从而影响训练的收敛速度。因此如果这里统一成平均值是0、方差为1的标准正态分布,会减小训练开销,得到更好的训练结果。这一点在深度学习图像处理中尤为关键,因为图像的像素值大小是0~255,如果直接使用则距离计算机喜欢的标准正态分布有些差距,所以通常会将像素范围调整在[-1, 1]之间,或者直接处理成标准正态分布。

这里需要注意,在实际处理过程中,初学者容易忽略的一点是对训练集、验证集、测试集分别计算不同的平均值与标准差,然后分别减平均值除标准差。这里应该统一减去训练集的平均值和标准差,因为首先我们可以认为是从训练集中估计了整体分布的特点,其次这样做也避免了引入更多验证数据后平均值标准差变化造成的影响。

最后我们放上sklearn在这一部分的用法:

2.3.2 第二步,挖掘数据特征

特征工程是整个建模过程的重中之重,通常建立一个数学模型,70%以上的时间都是投入在数据挖掘环节中的。

我们挖掘特征的原因是为了让计算机可以更好地理解数据。要想让计算机理解数据,数据科学家就需要首先理解数据。这种理解,在实际运用的过程中是离不开具体业务逻辑支持的。例如,医学领域的统计学家统计了各种疗法对降低血糖的效果,希望建立一个推荐高血糖治疗方法的模型,最后发现打胰岛素见效快、效果好。而在实际的医学临床实践中,打胰岛素是最迫不得已的一种治疗方法,如果有更好的选择,医生绝对不会推荐这种方法。因此,虽然现阶段人工智能不断地在各个领域取得很好的表现,但是如果想要在复杂的应用场景落地,还是需要有人类专家的支持与帮助。

正是由于这一部分内容涉及面太广,不属于入门内容,并且我们后文的深度学习部分主要强调的是用深度神经网络自动挖掘特征,因此这部分内容将用最简单的例子讲一讲。

在二维平面上以原点为圆心,在两个圆环的范围分别随机生成与原点距离不同的两组点。其中里面圆环上的点是第二组,外面圆环的点是第一组。我们看看如何挖出一个简单的、线性可分的特征来区分这两组点:

看图应该更加直观:

其结果如图2-10所示。

图2-10 查看分布点

对特征组合做图发现,如果使用单一特征的话,二者是混合在一起的。两个特征直接进行组合的话,二者之间仍然线性不可分——两个分类被一个圆形隔开了,一条线性的直线切不开两者。

    sns.pairplot(pd_circ, hue="label")

其运行结果如图2-11所示。

图2-11 运行结果

这时可以手动进行一些特征工程。简单试一下加法和乘法(X+Y、X*Y),由于和圆形有关,我们再试下X*X+Y*Y:

其运行结果如图2-12所示。

图2-12 X*X+Y*Y的结果

注意右下角的图会发现,我们挖掘的X*X+Y*Y这个特征,单独一个特征已经是线性可分的了,这极大地降低了计算机模型将二者分开的难度。

读者可能会问,难道计算机只认识线性可分、不认识圆形边界吗?如果有成百上千个特征,难道数据科学家在成百上千个特征基础上手动组合各种可能性?实际上计算机当然可以认出圆形的边界,这里只是很简单的特征工程例子,计算机同样可以借助数学模型实现。比如这里圆形边界的例子,就可以通过计算两个类群的高斯分布特征,进而借助高斯核函数实现分割:

以高斯分布来拟和各个类群XY的分布,继而通过高斯分布给出的概率得出的分类结果是pred列,而pred列中给出的结果与实际结果是基本符合的。可见借助算法模型,计算机可以实现多个特征的组合。但是这种组合往往缺乏针对性,如果人类专家能在此手动挖掘几个关键特征,“提示”计算机一下,将更加可能得到好的结果。比如计算机并不直接认识文本、年月日、经纬度、人物关系等,需要人类专家在现有数据基础上,根据需要做一些基本转换,这些信息才可以被有效利用。

最后说两点在实际特征工程进行中入门者需要注意的事项:

(1)对于离散特征,使用one-hot编码。

例如,对于这种输入:

我们想用数字来表示职业。很多初学者会用这种错误的方法来表示:

这种方法错误的原因是,如果用连续的数字来表示不同职业,计算机会认为这些数字存在大小关系,由于1<2<3,因此工人<农民<军人,这种观点当然是错误的,所以这里相当于是给了模型一个经过错误处理的输入数据。对于这种情况,我们使用one-hot编码来表示。如果用one-hot,这里正确的表示方法就是某个人是不是工人、是不是农民、是不是军人:

(2)特征工程其实是个头脑风暴的过程。在开始阶段,特征要尽可能多,到了后期,则要尽可能地选择最重要的特征用于模型训练。这种选择可以通过在模型中引入正则化来完成,至于多保留特征还是多舍弃特征,这里可以通过调整正则化常数来实现,调整结果的好坏可以进一步在验证集中的表现来确认。

初学者可能会忽略这一点,看见模型预测准确率在训练集中很高,一看准确率99%就以为训练成功,忘记在验证集中确认模型的表现。如果此时验证集的表现并不好,数据就发生了过拟合现象。我们用应试教育的例子来类比的话,一个学生平时作业准确率很高,他的学习方法就是“背答案”,而且背得很准,见过的题目全部都知道答案,但是题目稍微变一下,就不会做题了,于是考试时拿到新题目,准确率就下来了。这种现象归根结底是无法很好地适应未知情况。

同样,用监督学习的名词来替换应试教育,见过的数据都能预测对,没见过的准确率大幅降低,这种情况也是由于数据不能合理地适应未知情况。这种模型并不是我们需要的结果。

最后,过拟合的前提是,学生平时成绩很好,考试没发挥好。如果平时成绩就不好,考试也没考好,这种情况属于欠拟合。如果发生欠拟合,引入正则化就不是那么紧迫了,我们应该更多关注关键特征是否被正确挖掘、模型是否合理、数据是否充足等。我们举一个多项式回归的例子,图中是在用多项式拟合加入噪声的cos曲线的一部分,左图是一次多项式拟合,显然由于一次多项式是线性的,拟合曲线肯定不够合理,于是发生了欠拟合;中间的使用4次多项式,看起来不错;而右边的十次多项式拟合十个点,结果看起来误差更小、更完美。但是假如再从cos函数中抽取若干点,这条线拟合的效果就会差很多,因此属于过拟合的情况,需要用正则化减少多项式的次数。有关正则化具体如何实现,下一部分讲解使用模型时将进一步介绍。

其运行结果如图2-13所示。正则化系数过高(左)、过低(右)都会影响拟合的效果。

图2-13 多项式曲线拟合过程中引入正则化

2.3.3 第三步,使用模型

这一步就是大家通常所说的“调(diao)包”以及“调(tiao)参”了,即调用算法包中的现有模型,通过调整模型参数,使模型在数据集中得到较好的表现。本书主要介绍的深度神经网络也是一种模型,后文将会详细介绍这一点。

经常有人说机器学习从业人员就是在调包和调参,这个观点其实是值得商榷的。因为首先如上文所述,有经验的数据科学家在拿到数据后,主要的精力是放在数据挖掘上,再进一步说,如果考虑数据的收集环节,那么数据科学家大部分精力并不是放在模型上,而是放在数据的收集、整理、清洗环节上。

给这种现象再深挖一层原因,这个问题其实出在监督学习有明确的评价标准上。由于标准明确,因此机器学习就有了套路,然后这个套路就被理解成了调包、调参。这个标准就是模型给出的结果和实际结果是否一致。这是一个很好理解的标准,比如老师要培养学生的个人品质、人生观、价值观,可能并不是一件容易的事情,如何培养一句话说不清楚;如果老师要提高学生考试成绩,就相对容易了许多,因为考试有明确的范围以及评价标准,只需要关注这部分内容对症下药即可,如同机器学习从业人员为了提高模型表现,使用不同模型、调整不同参数一样,虽然不好做,终归还是有套路的;如果要让模型打游戏,模型就需要对游戏中各种行为的收益做一个衡量,此时模型也没有公认明确的量化指标,而是上升到“人生观、价值观”的层面了,评价模型就如同评价学生个人品质一样,同样也是一句话说不清楚的。

这里将从评价标准讲起,从后往前简单说一下这部分内容。首先简单介绍逻辑回归的公式,进而根据评价标准讲一下模型的损失函数问题,最后说一下上一步的正则化如何影响这里的损失函数。由于本书的入门性质,我们仍然选择简单的讲,这里主要介绍逻辑回归模型。

1.逻辑回归的公式表达

虽然名字带了回归,但事实上,这里逻辑回归是一个有监督的分类问题。我们具体看一下逻辑回归做了什么。

接下来,本书将推出一些公式。初学者可能最怕的就是满篇的公式,为了方便读者理解,这里从高中课本开始说起。高中课本中有一个“一元二次回归”,形式如下:

注意,高中课本上的xy是一个数字,而实际上这里的x可以是一个长度是m的向量(vector)。背后的数学意义是,之前预测y只考虑一个因素,这里考虑m个因素,而这里的m个因素就可以是鸢尾花数据集中的四个特征(m = 4):

这里的公式用向量的形式重新定义:

其中

注意,向量通常是竖着写的,这里用了转置将其变成横向,读者或许有点懵,简单讲一下。首先,这里为了简化,向量ω里面多了一位bx里面多了一位1,这样就可以把常数项放进来,使公式更加简洁。其次,这里使用了线性代数中矩阵的乘法,由于我们的结果y只有一个数字,不妨认为它就是一个1×1的矩阵。根据矩阵乘法的原则,两个矩阵相乘,前面一个的行数定义结果有多少行,后面一个的列数定义结果就有多少列,所以m+1行1列的ω要变成1行m+1列的形式,这样结果才会是1×1的结果。

逻辑回归做的就是对这个结果进一步变化:

我们关注f(x) = sigmoid(x)的形式:

其实对于绝大多数的输入x(绝对值大于5),sigmoid函数都会返回一个非常接近0或者1的结果,只有x取值范围在[-5, 5]之间时才会是其他值。正是由于这种特性,我们可以近似认为sigmoid函数的返回值就是0或者1,这种离散化就是逻辑回归“名曰回归,实则分类”的原因——我们就可以认为,这里的y代表了某个样本是否属于某个分类的概率,例如鸢尾花分类问题,对一个样本,我们可以对四个特征先进行线性回归,算出一个数,再进一步进行逻辑回归,判断这个样本属于某一分类的概率。注意,这里真实的y是一个非0即1的数字。我们预测的结果ŷ则是逻辑回归函数的纵坐标——取值范围[0,1]的一个概率值。

此时,读者心里可能会有一个疑问:逻辑回归函数中ω是怎么算出来的?可以猜吗?这里确实需要猜一下,其中的算法大概是这样的:

(1)随机初始化一组ω,比如可以全部设为0,当然实际上不推荐这样。

(2)在训练集中,向逻辑回归函数里输入特征x,计算,得到预测结果

(3)计算全部训练集中逻辑回归的结果和实际y的差别。

(4)根据上一步的差别更新ω

(5)重复(2)~(4)若干次(iterations)。

2.损失函数——如何表示预测ŷ和实际y之间的差别

回顾一下我们现在会做什么。首先,猜一组数字,当然会做(当然第5章讲述卷积层时还会介绍深度神经网络中随机初始化需要注意的事项)。其次,乘法、加法和sigmoid函数也会写,关键是第三步和第四步,如何表示预测和实际y之间的差别,逻辑回归这里引入了交叉熵的概念。

关于交叉熵的相关概念,首先这里的熵指的是信息熵。信息熵是对不确定性的衡量,具体而言,这里引用吴军老师《数学之美》一书中的一段描述:

当我错过了上一届世界杯的比赛,而想知道谁夺得冠军时,我询问一个知道比赛结果的观众。但是他并不愿意直接告诉我,而是让我猜测,每猜一次他要收费1元来告诉我,我的猜测是否正确。那么我要花多少钱才能知道谁是冠军呢?

我可以把球队编号,1到32号(当然大家都知道世界杯是32支球队,然而过几年变成48支的时候我会回来修改的)然后我提问:“是在1到16号中吗?”。如果他告诉我猜对了,我会继续问:“是在1到8号中吗?”。这种询问方式大家都懂,因此这样询问下去,只需要5次,也就是只需要5元钱就可以知道哪支球队是冠军。

因此,世界杯冠军这条消息的信息量可以看作是5元钱。我们回到数学上的问题,使用比特来代替钱的概念(计算机中,一个比特是一位二进制数,一个字节就是8个比特),这条信息的信息量是5比特。如果有64支队伍,就要多猜一次,也就是6比特。

可见这里参赛球队越多,冠军归属这条消息的信息熵就越高。同时也要注意,这里信息熵的求法,背后的假设是各球队夺冠的概率相等,而实际情况并非如此,虽然64支队伍参赛,但具备夺冠实力的球队只是个位数,因此实际的信息熵是低于这个数字的。

解释完信息熵,我们再来谈一谈什么是交叉熵。交叉熵用来衡量两个正函数是否相似,对于两个完全相同的函数,它们的交叉熵等于零。如果是考虑分类问题中预测的概率ŷ和实际概率y之间的差别,当预测的概率与实际情况一致时,交叉熵即为0。具体对某个样本而言,定义其交叉熵为:

这里的K代表K个最终分类,如鸢尾花数据集中最终对三种花分类,则K=3。

如果是二分类的情形,此时K=2,就有:

我们简单地预览一下二分类情况下交叉熵的性质,如果真实的分类结果是y=0,我们看看不同的ŷ下交叉熵的取值:

    y = 0
    np_yhat = np.linspace(0, 1, 101)
    np_h = -(y*np.log(np_yhat) + (1-y)*np.log(1-np_yhat))
    plt.plot(np_yhat, np_h)

可见我们预测的ŷ和真实的y越接近,即预测得越准确,交叉熵将会越接近0。相反,如果预测值ŷ和真实的y完全相反,实际不是这种分类情况(y = 0),预测时却100%判断是1(ŷ = 1),交叉熵的值就会接近正无穷大。

以上内容只是考虑一个样本的情况。当考虑多个样本时,每个样本都可以计算一个交叉熵,此时就可以用全部样本的平均交叉熵作为损失函数(Loss function)来衡量模型预测的准确程度:

简单回忆一下,最右边的式子中总共有N个样本K个分类,在鸢尾花数据集中,就是N=150、K=3。yik是第i个样本第k个分类,如果这个样本属于第0个分类,那么yi,k=0=1,yi,k=1,2=0。ω一共有K组,每组都是长度为M+1(M是特征数,如鸢尾花数据集M=4)的向量。在实际计算中,ω真正需要K-1组即可,比如二分类的话,预测一类后另一类的概率也就知道了,由于只预测一类,因此使用一组ω即可。

可能读者被这里的数学公式给吓到了,再用通俗一点的语言简单进行总结。其实这里需要交叉熵回答的问题是对于每个样本的分类结果,模型给出的预测与实际情况有多大的区别。所以我们可以将交叉熵理解成机器学习模型的KPI、GPA这样的可量化考勤指标,模型每预测一次,就用交叉熵来考勤一次。如果模型的考勤结果不好怎么办?如何改进下一步的工作?请看下一部分内容。

3.如何根据预测ŷ和实际y之间的差别更新参数ω

此时,我们就得到了第三步中“计算全部训练集中,逻辑回归的结果ŷ和实际y差别”。我们可以基于这种差别,进一步更新ω的值:

其中,t代表迭代次数,因为这里更新值并不是一步完成的,可能迭代了上百次;α是学习率,用来控制迭代的步长,这里需要根据数据进行一定调整,过小会导致训练缓慢,过大则会造成结果精度不足。

剩下的问题就是求偏导数了。这里引入链式求导法则。为了简化操作,这里只考虑K=2,即二分类情况,有:

进一步化简,将yi进行向量化、将xi进行矩阵化以消除求和项:

进行简单的化简,令:

利用导数的定义以及链式求导法则,则有:

根据:

带回公式,化简得到:

这里继续来拯救被公式吓懵的读者。前面说到交叉熵损失函数实际就是KPI、GPA这样的量化考勤指标,如果想提高得分,应该怎么办?最简单的方法就是看看指标中哪一项得分低——比如考试分数,数学考了99分、英语60分,我们就可以认为数学成绩相比100分满分的差距()是1、英语是40,那么想提高考试成绩的话,下一阶段就需要将主要的时间精力放在英语上。我们也不能在下一阶段学英语学得太猛而影响总体成绩,所以需要乘以一个学习率α

4.几点思考

至此,我们完成了逻辑回归的主要理论部分。如果读者没有被公式绕晕、坚持到了这里,就从逻辑回归的理论出发,简单谈谈其他的监督学习公式。首先回顾一下逻辑回归的步骤:

(1)随机初始化一组ω,比如可以全设为0,当然实际上不推荐这样。

(2)训练集中,在逻辑回归函数里输入特征x,计算,得到预测结果ŷ

(3)计算全部训练集中,逻辑回归的结果ŷ和实际y差别。

(4)根据上一步的差别更新ω

(5)重复(2)~(4)若干次(iterations)。

现在的问题是,如果要改动这几个步骤变成一个新算法,可以怎么改?我们注意到,实际上可以改动的地方主要是第二、三步,也就是说,可以有这些思路:

  • 预测结果时,把逻辑回归sigmoid函数换成一个其他的函数。
  • 计算损失时,换成一个损失函数。

这两个步骤通常是同时变换的,在算法层面二者共同推导得到。如支持向量机,就是把逻辑回归的sigmoid函数换成核函数,损失函数由平均交叉熵换成了不同分类的距离间隔。又如朴素贝叶斯,预测结果基于概率判断,损失函数同样基于概率判断。本书不再重点讨论这部分内容。

本书后面内容将详细介绍的深度学习算法则基本沿袭了逻辑回归的思路,只改了步骤(2),将原本一个逻辑回归函数变成几十个函数的嵌套,然后利用链式求导法则对嵌套的几十个函数进行反向求导,得出损失函数。然后对其他步骤做了一些工程创新,使其可以适应更大规模数据。

5.正则化

前面提到,过多的参数会导致过拟合,因此可以在规定损失函数的时候,将这一点考虑进来:

Loss =正则化系数(C) ×分类准确率罚分项+过多参数罚分项

在上一步中其实也注意到,逻辑回归随机了一个初始化的系数ω后,接着借助求导进行梯度下降,就可以得到最终解,需要的额外参数只有α。而实际工程运用中,借助libfgs sag等梯度下降求解工具,我们甚至也不需要提供α值。因此似乎逻辑回归不需要提供额外的超参数。实际上,如果考虑正则化,就需要关注正则化系数C的影响。因此,逻辑回归调参主要调的就是这里的C值,过小的C会过度强调罚分项的损失而非对模型预测结果的关注,造成欠拟合,而过大的C则会过分强调结果,可能会造成参数数目过多,进而造成过拟合。

这里的过多参数罚分项有两种比较常见。

一种是各项系数的绝对值相加,即L1正则化:

另一种是使用L2正则化:

此时,求导的话,导数将会分别变成:

这里sgn(ω)代表ω正负号。

继续拯救被公式绕晕的读者们,我们知道KPI、GPA的考核指标虽然是越多越全面越好,但如果搞出几百项考核指标来,首先这些指标的内容就不好理解,让人无法根据结果得分做下一阶段的规划;其次这些考核指标是否全部合理也是问题。因此考核指标需要简化,机器学习中就使用了正则化策略来简化考核指标的复杂性。最后,再解释一下L1正则化与L2正则化的区别。相比L2正则化,加入L1正则化后,优化得到的ω向量,会具有更高的稀疏性,即向量的很多参数会是0。而L2正则化后,优化得到的向量参数则会是一个接近0的、很小的参数。具体原因是在L2正则化中,损失函数对ω的偏导数会随着ω的值减小而不断减小,梯度下降速度越来越慢,因此最后结果接近但不等于0。而L1正则化的梯度,则只和ω的正负有关,与其本身值大小无关,因此梯度下降速度始终会保持一个最小值,保证最终结果的稀疏性。

本书在5.4节会结合深度神经网络,再次讨论利用正则化、防止过拟合的问题,请读者留意。

2.3.4 第四步,代码实战

本节将根据之前讲述的部分造一个轮子以方便大家理解,然后给出sklearn的代码,用于实战时使用。

运行结果:

          # out:
          array([[-16.8213461 ],
          [-39.77445862],
          [ 62.60998404],
          [ 30.07176958],
          [ -8.52757522]])

预览结果:

          plt.plot( 1 / (1+np.exp(-X.dot(omega))))

结果中前50个样本被预测为分类0,即setosa,其他的被预测为非setosa,与预期相同,造轮子完成。

实战使用时,我们可以直接调用sklearn的相关包,发现结果同样准确:

    from sklearn.linear_model import LogisticRegression
    model = LogisticRegression(C=1)
    model. fit(X, y)
    plt.plot(model.predict(X))

1.K折交叉与网格搜索

之前的代码其实存在一些问题,我们前面强调过,但是在代码中并没有体现,大家应该也注意到了:

(1)训练集和测试集要隔离,而上一部分代码测试用的数据完全就是训练集,这样很容易过拟合。

(2)正则化系数是相当重要的参数,这里直接用C=1是否合理?

因此,为了解决问题1,我们引入K折交叉,将数据平均分成K份,K-1份拿来训练,1份看结果,然后重复K次,用这种方法实现训练集和测试集的隔离;为了解决问题(2),我们引入参数的网格搜索(Grid Search),尝试不同参数的选择,寻找最优的一种。

由此可见,这里不存在过拟合问题,10折交叉验证自动生成的训练集、验证集预测准确率高度重合。C=0.0001, 0.001时会由于C过小、对预测结果的关注不足造成欠拟合问题。我们之前用的C=1其实是碰巧用了合适的参数。

更多内容,读者可以参考作者博客文章https://zhuanlan.zhihu.com/p/25637642。

2.评价不平衡样本分类结果

之前根据准确率优化模型,如果数据分布不平均,单纯地使用错误率作为标准会产生很大的问题。比如某一种罕见疾病的发病率是万分之一(0.01%),这时如果一个模型什么都不管,直接认为这个人没有病,也能拿到一个99.99%正确的模型。这种情况下,模型预测准确率是很高,但却没有什么实际价值。那么,应该如何正确衡量准确率的这个问题呢?如果是经典的二分类问题,这种情况下需要综合考虑不同标准下的灵敏度以及假阳性率

理解这两个概念之前,我们要明确一点,就是与医生直接判断某一患者是否有病相比,模型给出的是否有病推论,是一个概率,这时可以选择一个判断有病的阈值,比如1%,即1%可能有病的情况下即判断为有病,和真实情况对比后得到如下的二联表:

在此基础上有:

真阳性率TPR:在所有实际为阳性的样本中,被正确地判断为阳性的比率。

假阳性率FPR:在所有实际为阴性的样本中,被错误地判断为阳性的比率。

然后在从0%到100%区间取多个阈值,得到不同的FPR/TPR值,以FPR为x轴、TPR为y轴,就可以得到一条ROC曲线,继而计算ROC围成的面积——AUC值。这种情况下可以认为,AUC值越高越好,最高可以是1。如果AUC值接近0.5,则分类器等于随机猜测。遇到特别的情况,如果AUC接近0,则很可能预测与真实情况完全反了,当然这种情况基本很少出现。

注意这里AUC越高越好和最小化损失函数这两个概念。可能某个模型的损失函数已经最小化了,但是AUC却不高,造成模型在实际使用时会引入很多错误——一个较低的AUC值,可能会在追求高灵敏度时引入大量的假阳性,其后果就是医生通知了十个患者有患癌风险,最终可能只有一个真有问题,其他九人虚惊一场。这种情况就是模型并未被很好地训练,可能存在着欠拟合的问题。同时,也可能损失函数最小化以后,测试数据AUC也很高,但是实际运用在真实案例中却又有大量的错误,就是所谓的过拟合了。

如果损失函数无法满足我们的评价标准(高AUC值),此时需要做的一件事就是调整损失函数,比如给数量较少类别的样本赋予更高的权重等。那么为什么不直接用AUC值作为优化目标呢?原因很简单,损失函数和整个模型的结构是偶联的,AUC值虽然作为评价指标很好,但是计算步骤相对要麻烦很多,也不利于向模型中传播误差梯度,所以一般不直接优化AUC值,而是用均方误差(MSE)、交叉熵(Cross Entropy)等更容易计算的指标进行优化。

使用sklearn计算阈值的方法: