0x12 模型评估,交叉验证

机器学习的目的,就是让程序从已知的数据中自己找出规律,然后将规律应用到未知的数据中去。构建机器学习模型时,最重要的部分便是模型的评估。一个模型没有经过交叉验证的评估,那么得出的准确率都是不太可靠的。模型评估中,除了训练数据和测试数据,还会涉及到验证数据。

0x12.jpg

01 测试与训练

机器学习的目的,就是要让程序从已知的数据中自己找出规律,然后将规律应用到未知的数据中去。不同于常规程序的步骤,由程序员事先设置好各种条件与跳转指令或者步骤,由程序一步步执行,直到程序结尾。机器学习的程序,程序员只负责设计程序如何去学习,至于学到什么规律,那主要是由给定的数据来决定的。再将学到的规律,应用到未知的数据集上去,这才是机器学习的核心魅力。

这其中便涉及两份数据集,一份给“机器”用于学习的数据,通常也叫训练数据集(training data),机器学习到的知识,通常叫模型。最后机器使用学习到的模型,对未知数据进行预测,这份数据通常叫测试数据(testing data)。因此,在程序中,会看到大量的train和test相关的变量,基本上的意思都指训练数据与测试数据相关。

比如,有一份数据如下:


知识星球.jpeg
序号 身高 房子 车子 长相 工作 约否
1 1.80 6.5 fact
2 1.62 5.5 IT
3 1.71 8.5 bank
4 1.58 6.3 bank
5 1.68 5.1 IT 不约
6 1.63 5.3 bank 不约
7 1.78 4.5 IT 不约
8 1.64 7.8 fact 不约

这份数据是过往的约会记录,全部信息都是来自于真实的记录,本身并不需要我们进行预测。我们的目的,是希望通过这份数据,来构建一个预测模型,预测一个新的对象会不会约会的模型。

那么,问题来了:构建机器学习模型时最重要的是什么?是模型的评估,即如何评价一个模型的好坏,或者说模型的准确率(或者误差率)到底如何。当然,如果还有另外一份过往的记录数据,我们可以用上面8条数据构建一个模型,然后用那份记录来进行测试,看预测的结果和记录的结果相同的次数,从而计算模型的准确率。

但问题是,假定只有这8条过往的记录,没有更多的数据,如何评价构建的模型的好坏呢?聪明如你,肯定已经想到了。可以把这8条记录分成两份,第一份为6条数据,第二份为2条数据,用第一份的6条数据来构建预测模型,然后将模型应用到第二份的2条数据,进行预测。预测时只需要传前面5个特征,最后的“约”与”不约“不作为特征,这个正是要预测的结论。看预测的“约”与“不约”结论是否和本身的记录一致,如果2条预测结果与原来数据记录的结果都一致,那么说明模型准确率为100%;如果只预测对一条,那么为50%;如果全部预测错误,那么模型准确率为0,此时就需要回过头去分析一下,看模型是否用对,或者参数是否都设置正确了。

02 交叉验证

验证模型准确率,是机器学习非常重要的内容。前面将数据手工切分为两份,一份做训练(train),一份做测试(test)便是最常用的手段。

术语上,叫交叉验证(Cross Validation),上面的方式,便是其中的“留一手”(Hold-Out)交叉验证。

交叉验证,在scikit-learn中,位于sklearn.cross_validation包中,而”留一手“的方式,使用train_test_split方法很容易实现:

from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)

其中的X为特征数据,y为响应变量,test_size=0.1表示将数据按90%的训练与10%的训练比例进行划分。因为程序会对原数据进行随机切分,而设置random_state是为了在对程序进行调试的时候,能保证每次都按固定的随机序列进行划分。

上面的“留一手”划分方式,通常留下的“一手”不只一个。还有极端的情况,“留一个”(Leave-One-Out),即只保留一条数据作为测试数据,剩下全部用于训练模型。训练好的模型,用这留下的一条数据来进行训练,在分类上,准确率要么是0,要么是100%。

当然,睿智如你般,肯定也想到了,上面的方式也有局限。因为只进行一次测试,并不一定能代表模型的真实准确率。因为,模型的准确率和数据的切分有关系,在数据量不大的情况下,影响尤其突出。自然,前辈们也早就想到了,并提出了比较好的解决方案。

那就是采用K折(K-Flod)交叉验证,将数据随机且均匀的分成K份,常用的K为10,数据预先分好并保持不动。假设每份数据的标号为0-9,第一次使用标号为0-8的共9份数据来作训练,而使用标号为9的这一份数据来进行测试,得到一个准确率。第二次使用标记为1-9的共9份数据进行训练,而使用标号为0的这份数据进行训练,得到第二个准确率,以此类推,每次使用9份数据作为训练,而使用剩下1份进行训练,这样共进行10次,最后模型的准确率为10次准确率的平均值。这样便避免了由于数据划分而造成的评估不准确的问题。

K-Flod交叉验证的方式,经常在实际的项目中使用。通常一个模型没有经过K-Fold的评估,那么得出的准确率都是不太可靠的。

也可以在K-Fold交叉验证的时候使用“留一个”的方式,即训练多个模型,让每条数据都有机会作一次测试,而除了作为测试的那条数据外,剩下的全部用于训练。这样有多少条数据,就训练多少个模型,然后这些模型的平均准确率为最后模型的准确率。但因为这样的训练代价太高(通常是太费时),实际上估计很少采用。

03 验证数据

使用训练数据与测试数据进行了交叉验证,只有这样训练出的模型才具有更可靠的准确率,也才能期望模型在新的、未知的数据集上,能有更好的表现。这便是模型的推广能力,也即泛化能力的保证。

除了最常用的training data与testing data外,在一些算法中,还会用到validation data(验证数据),其作用和testing data差不多。

Validation data通常是直接应用于模型的构建过程中,尤其是多次迭代的算法中,比如多层神经网络算法中,算法在每一轮迭代过程中,会更新网络连接中各层的权重值,当完成一轮更新过后,算法会使用验证数据(validation data)来进行一次验证,以测试在这份数据上,算法的改进效果。

和testing data的主要区别,是验证数据用来调整模型的参数,以及用来设置提前停止(Early stop)的条件,比如在深度学习框架keras中,有如下示例代码:

save_best = ModelCheckpoint('model.nn', verbose=1, save_best_only=True)
early_stop = EarlyStopping(monitor='val_loss', patience=10, verbose=1)
model.fit(X_train, y_train,
    batch_size=64,
    nb_epoch=100,
    show_accuracy=False,
    validation_split=0.1,
    callbacks=[save_best, early_stop],
    verbose=1)

说明:

  1. 通过参数validation_split来设置在训练数据中分出10%来作为验证数据,剩下90%作为训练数据。
  2. 通过定义两个回调函数,early_stop这个回调方法,就是指让程序监控val_loss(validation loss)这个条件,容忍度为10次,即在迭代10次的过程中,在验证数据上的验证效果(通过val_loss体现)都没有改善(降低),那么就停止运行。
  3. 另外一个回调方法save_best保证在每轮迭代的过程中,只要在验证数据上效果有改善,就将训练好的模型进行覆盖保存,没有改善则不保存。这样保证在early_stop退出的时候,保存的模型是训练过程中最好的。

04 OOB数据

随机森林(Random Forest)算法中,在构建每颗树的时候,对原始数据都是采取的有放回抽样,根据统计发现,每次都有大约1/3的数据不会被选中,即用于构建每颗决策树的数据都大约只有原数据的2/3,那么其中的1/3未被选中的数据,也就叫袋外数据OOB(Out Of Bag)。

这部分数据没有参与构建决策树,正好可以被利用来对模型进行评估。它甚至可以取代前面使用的测试集来评估模型误差,因为它并没有参与模型的训练,正是天然的测试数据。每颗树的OOB数据都是不太相同的,测试的时候,也是用每颗树自己的OOB数据来进行测试,最后组合所有OOB数据的测试结果,并求平均(回归问题)。

在scikit-learn的随机森林中,参数oob_score(bool型),用于配置是否使用oob样本来评估模型的泛化误差的参数。当设置为true后,在最后的模型上,即可以通过 oob_score_ 这个属性来打印模型的oob分数。oob_score_这个属性,获取的是使用OOB数据测试的R2(判定系数)分数,也即是在oob_prediction_数据上的R2分数。

知识星球.jpeg

比如,一共有10颗树,第一颗没有被选中的袋外数据(OOB)为编号1,5,8,9,那么就用这些编号的数据,来对第一颗树进行测试,得出的值为y11,y15,y18,y19 (第一个下标为树的编号,第二个下标为数据编号),依此类推。测试全部的10颗树,其中可能编码为1的数据,测试了2次,最后求两次的平均(回归问题),即为编码为1的数据在随机森林模型中的预测值。将所有的OOB数据的预测值与真实值求一次R^2系数,即为模型oob_score_的值。

另外,如果需要对训练数据本身的预测,也需要使用oob_prediction_这个属性,这个属性是使用oob的样本来对模型进行预测,而不是训练数据。如果直接将训练数据送入predict()方法中去,得出的结论和原来的基本上是一样的,因为完全生长的决策树,会简单的存储所有的分支,使用训练数据构建得出的决策树,再对训练数据进行测试,结果当然不会变。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容