转载:https://www.toutiao.com/i6435866304363627010/git
笔者参加了由Quora举办的Quora Question Pairs比赛,而且得到了前1%的成绩。这是笔者Kaggle首战,因此写下此文来系统化地梳理比赛的思路,而且和你们分享咱们参赛的一些心得。算法
Quora Question Pairs是一个天然语言(NLP)比赛,比赛的题目能够简单地归纳为“预测两个问句的语义类似的几率”。其中的样本以下:数据结构
打Kaggle比赛的大体套路(比赛篇)框架
咱们队伍和其余出色队伍的参赛经验(经验篇)dom
完成Kaggle比赛须要学会哪些实用的工具(工具篇)机器学习
1.1 分析题目ide
拿到赛题之后,第一步就是要破题,咱们须要将问题转化为相应的机器学习问题。Kaggle最多见的机器学习问题类型有:函数
回归问题工具
分类问题(二分类、多分类、多标签):多分类只需从多个类别中预测一个类别,而多标签则须要预测出多个类别。性能
好比Quora的比赛就是二分类问题,由于只须要判断两个问句的语义是否类似。
1.2 数据分析
所谓数据挖掘,固然是要从数据中去挖掘咱们想要的东西,咱们须要经过人为地去分析数据,才能够发现数据中存在的问题和特征。咱们须要在观察数据的过程当中思考如下几个问题:
数据应该怎么清洗和处理才是合理的
根据数据的类型能够挖掘怎样的特征
数据中的哪些特征会对标签的预测有帮助
1.2.1 统计分析
对于数值类变量,咱们能够获得min,max,mean,meduim,std等统计量,用pandas能够方便地完成,结果以下:
从上图中能够观察Label是否均衡,若是不均衡则须要进行over sample少数类,或者down sample多数类
咱们还能够统计数值类变量之间的相关系数,用pandas就能够轻松得到相关系数矩阵:观察相关系数矩阵可让你找到高相关的特征,以及特征之间的冗余度。而对于文本变量,能够统计词频(TF),TF-IDF,文本长度等等
1.2.2 可视化
人是视觉动物,更容易接受图形化的表示,所以能够将一些统计信息经过图表的形式展现出来,方便咱们观察和发现。好比用直方图展现问句的频数或者绘制相关系数矩阵:经常使用的可视化工具备matplotlib和seaborn。固然,你也能够跳过这一步,由于可视化不是解决问题的重点。
1.3 数据预处理
刚拿到手的数据会出现噪声,缺失,脏乱等现象,咱们须要对数据进行清洗与加工,从而方便进行后续的工做。针对不一样类型的变量,会有不一样的清洗和处理方法:
对于数值型变量,须要处理离群点,缺失值,异常值等状况
对于类别型变量,能够转化为one-hot编码、实体嵌入、哈希编码
文本数据是难处理的数据类型,有垃圾字符,错别字词,数学公式,不统一单位和日期格式等。咱们还须要处理标点符号,分词,去停用词,对于英文文本可能还要词性还原(lemmatize),抽取词干(stem)等等。
1.4 特征工程(Feature Engineering)
都说特征为王,特征是决定效果最关键的一环。咱们须要经过探索数据,利用人为先验知识,从数据中总结出特征。
1.4.1 特征抽取(Feature Extraction)
咱们应该尽量多地抽取特征,只要你认为某个特征对解决问题有帮助,它就能够成为一个特征。特征抽取须要不断迭代,是最为烧脑的环节,它会在整个比赛周期折磨你,但这是比赛取胜的关键,它值得你耗费大量的时间。
那问题来了,怎么去发现特征呢?光盯着数据集确定是不行的。若是你是新手,能够先耗费一些时间在Forum上,看看别人是怎么作Feature Extraction的,而且多思考。虽然Feature Extraction特别讲究经验,但其实仍是有章可循的:
对于Numerical Variable,能够经过线性组合、多项式组合来发现新的Feature
对于文本数据,有一些常规的Feature。好比,文本长度,Embeddings,TF-IDF,LDA,LSI等,你甚至能够用深度学习提取文本特征(隐藏层)
若是你想对数据有更深刻的了解,能够经过思考数据集的构造过程来发现一些magic feature,这些特征有可能会大大提高效果。在Quora此次比赛中,就有人公布了一些magic feature
经过错误分析也能够发现新的特征,见1.5.2小节
1.4.2 特征选择(Feature Selection)
作特征抽取,尽量地抽取更多的Feature,但过多的Feature会形成冗余,噪声,容易过拟合等问题,所以咱们需特征筛选。特征选择能够加快模型的训练速度,甚至还能够提高效果。特征选择的方法多种多样,最简单的是相关度系数(Correlation coefficient),它主要是衡量两个变量之间的线性关系,数值在[-1.0, 1.0]区间中。数值越是接近0,两个变量越是线性不相关。可是数值为0,并不能说明两个变量不相关,只是线性不相关而已。
咱们经过一个例子来学习一下怎么分析相关系数矩阵:
相关系数矩阵是一个对称矩阵,因此只须要关注矩阵的左下角或者右上角。咱们能够拆成两点来看:
Feature和Label的相关度能够看做是该Feature的重要度,越接近1或-1就越好
Feature和Feature之间的相关度要低,若是两个Feature的相关度很高,就有可能存在冗余
除此以外,还能够训练模型来筛选特征,好比带L1或L2惩罚项的Linear Model、Random Forest、GDBT等,它们均可以输出特征的重要度。在此次比赛中,咱们对上述方法都进行了尝试,将不一样方法的平均重要度做为最终参考指标,筛选掉得分低的特征。
1.5 模型创建(Modeling)
1.5.1 模型
机器学习模型有不少,建议均做尝试,不只能够测试效果,还能够学习各类模型的使用技巧。其实,几乎每一种模型都有回归和分类两种版本,经常使用模型有:
KNN
SVM
带惩罚项的Linear Model
ExtraTree
RandomForest
Gradient Boost Tree
Neural Network
这些模型都已经有现成的工具(如scikit-learn、XGBoost、LightGBM等)可使用。可是咱们应该要知道各个模型的原理,这样在调参的时候才会游刃有余。你也使用PyTorch/Tensorflow/Keras等深度学习工具来定制本身的Deep Learning模型。
1.5.2 错误分析
人无完人,每一个模型不可能都是完美的,它总会犯一些错误。为了解某个模型在犯什么错误,咱们能够观察被模型误判的样本,总结它们的共同特征,咱们就能够再训练一个效果更好的模型。这种作法有点像后面Ensemble时提到的Boosting,可是咱们是人为地观察错误样本,而Boosting是交给了机器。经过错误分析->发现新特征->训练新模型->错误分析,能够不断地迭代出更好的效果,而且这种方式还能够培养咱们对数据的嗅觉。
举个例子,此次比赛中,咱们在错误分析时发现,某些样本的两个问句表面上很类似,可是句子最后提到的地点不同,因此其实它们是语义不类似的,但咱们的模型却把它误判为类似的。好比这个样本:
Question1: Which is the best digital marketing institution in banglore?
Question2: Which is the best digital marketing institute in Pune?
为了让模型能够处理这种样本,咱们将两个问句的最长公共子串(Longest Common Sequence)去掉,用剩余部分训练一个新的深度学习模型,至关于告诉模型看到这种状况的时候就不要判断为类似的了。所以,在加入这个特征后,咱们的效果获得了一些提高。
1.5.3 调参
训练模型前,咱们须要预设一些参数来肯定模型结构(好比树的深度)和优化过程(好比学习率),这种参数被称为超参(Hyper-parameter),不一样的参数会获得的模型效果也会不一样。老是说调参就像是在“炼丹”,像一门“玄学”,可是根据经验,仍是能够找到一些章法的:
根据经验,选出对模型效果影响较大的超参
按照经验设置超参的搜索空间,好比学习率的搜索空间为[0.001,0.1]
选择搜索算法,好比Random Search、Grid Search和一些启发式搜索的方法
验证模型的泛化能力:详见下一小节
1.5.4 模型验证(Validation)
Test Data的标签未知的状况下,咱们须要本身构造测试数据来验证模型的泛化能力,所以把Train Data分割成Train Set和Valid Set两部分,Train Set用于训练,Valid Set用于验证。
简单分割
将Train Data按必定方法分红两份,好比随机取其中70%的数据做为Train Set,剩下30%做为Valid Set,每次都固定地用这两份数据分别训练模型和验证模型。这种作法的缺点很明显,它没有用到整个训练数据,因此验证效果会有误差。一般只会在训练数据不少,模型训练速度较慢的时候使用。
交叉验证
交叉验证是将整个训练数据随机分红K份,训练K个模型,每次取其中K-1份做为Train Set,留出1份做Valid Set,所以也叫作K-fold。至于这个K,你想取多少均可以,但通常选在3~10之间。咱们能够用K个模型得分的mean和std,来评判模型得好坏(mean体现模型的能力,std体现模型是否容易过拟合),而且用K-fold的验证结果一般会比较可靠。若是数据出现Label不均衡状况,可使用Stratified K-fold,这样获得的Train Set和Test Set的Label比例是大体相同。
1.6 模型集成(Ensemble)
曾经听过一句话,“Feature为王,Ensemble为后”。Feature决定了模型效果的上限,而Ensemble就是让你更接近这个上限。Ensemble讲究“好而不一样”,不一样是指模型的学习到的侧重面不同。举个直观的例子,好比数学考试,A的函数题作的比B好,B的几何题作的比A好,那么他们合做完成的分数一般比他们各自单独完成的要高。
常见的Ensemble方法有Bagging、Boosting、Stacking、Blending
1.6.1 Bagging
Bagging是将多个模型(基学习器)的预测结果简单地加权平均或者投票。Bagging的好处在于能够并行地训练基学习器,其中Random Forest就用到了Bagging的思想。举个通俗的例子,以下图:
老师出了两道加法题,A同窗和B同窗答案的加权要比A和B各自回答的要精确。Bagging一般是没有一个明确的优化目标的,可是有一种叫Bagging Ensemble Selection的方法,它经过贪婪算法来Bagging多个模型来优化目标值。
Bagging Ensemble Selection:http://www.cs.cornell.edu/~alexn/papers/shotgun.icml04.revised.rev2.pdf1.6.2 Boosting
Boosting的思想有点像知错能改,每训练一个基学习器,是为了弥补上一个基学习器所犯的错误。其中著名的算法有AdaBoost,Gradient Boost。Gradient Boost Tree就用到了这种思想。我在1.2.3节的错误分析中提到Boosting,错误分析->抽取特征->训练模型->错误分析,这个过程就跟Boosting很类似。
1.6.3 Stacking
Stacking是用新的模型(次学习器)去学习怎么组合那些基学习器,它的思想源自于Stacked Generalization这篇论文。若是把Bagging看做是多个基分类器的线性组合,那么Stacking就是多个基分类器的非线性组合。
Stacked Generalization论文:http://www.machine-learning.martinsewell.com/ensembles/stacking/Wolpert1992.pdf
Stacking能够很灵活,它能够将学习器一层一层地堆砌起来,造成一个网状的结构,以下图:
举个更直观的例子,仍是那两道加法题:
这里A和B能够看做是基学习器,C、D、E都是次学习器
Stage1: A和B各自写出了答案
Stage2: C和D偷看了A和B的答案,C认为A和B同样聪明,D认为A比B聪明一点。他们各自结合了A和B的答案后,给出了本身的答案
Stage3: E偷看了C和D的答案,E认为D比C聪明,随后E也给出本身的答案做为最终答案
在实现Stacking时,要注意的一点是,避免标签泄漏(Label Leak)。在训练次学习器时,须要上一层学习器对Train Data的测试结果做为特征。若是咱们在Train Data上训练,而后在Train Data上预测,就会形成Label Leak。为了不Label Leak,须要对每一个学习器使用K-fold,将K个模型对Valid Set的预测结果拼起来,做为下一层学习器的输入。以下图:
由图可知,咱们还需对Test Data作预测。这里有两种选择,能够将K个模型对Test Data的预测结果求平均,也能够用全部Train Data从新训练一个新模型来预测Test Data。因此在实现过程当中,咱们最好把每一个学习器对Train Data和对Test Data的测试结果都保存下来,方便训练和预测。
对于Stacking还要注意一点,固定K-fold能够尽可能避免Valid Set过拟合,也就是全局共用一份K-fold,若是是团队合做,组员之间也是共用一份K-fold。
若是想具体了解为何须要固定K-fold,请看这里:https://mlwave.com/kaggle-ensembling-guide/
1.6.4 Blending
Blending与Stacking很相似
1.7 后处理
有些时候在确认没有过拟合的状况下,验证集上作校验时效果挺好,可是将测试结果提交后的分数却不如人意,这时候就有多是训练集的分布与测试集的分布不同而致使的。这时候为了提升LeaderBoard的分数,还须要对测试结果进行分布调整。
好比此次比赛,训练数据中正类的占比为0.37,那么预测结果中正类比例也在0.37左右,而后Kernel上有人经过测试知道了测试数据中正类的占比为0.165,因此咱们也对预测结果进行了调整(方法:我的以为能够调节断定正负的阈值),获得了更好的分数。
2 经验篇
2.1 咱们的方案
深度学习具备很好的模型拟合能力,使用深度学习能够较快得获取一个不错的Baseline,对这个问题总体的难度有一个初始的认识。虽然使用深度学习能够免去繁琐的手工特征,可是它也有能力上限,因此提取传统手工特征仍是颇有必要的。咱们尝试Forum上别人提供的方法,也尝试本身思考去抽取特征。总结一下,咱们抽取的手工特征能够分为如下4种:
Text Mining Feature, 好比句子长度;两个句子的文本类似度,如N-gram的编辑距离,Jaccard距离等;两个句子共同的名词,动词,疑问词等
Embedding Feature, 预训练好的词向量相加求出句子向量,而后求两个句子向量的距离,好比余弦类似度、欧式距离等等
Vector Space Feature,用TF-IDF矩阵来表示句子,求类似度
Magic Feature, 是Forum上一些选手经过思考数据集构造过程而发现的Feature,这种Feature每每与Label有强相关性,能够大大提升预测效果
咱们的系统总体上使用了Stacking的框架,以下图:
Stage1: 将两个问句与Magic Feature输入Deep Learning中,将其输出做为下一层的特征(这里的Deep Learning至关于特征抽取器),咱们一共训练了几十个Deep Learning Model
Stage2: 将Deep Learning特征与手工抽取的几百个传统特征拼在一块儿,做为输入,在这一层,咱们训练各类模型,有成百上千个
Stage3: 上一层的输c进行Ensemble Selection
比赛中发现的一些深度学习的局限:
经过对深度学习产生的结果进行错误分析,而且参考论坛上别人的想法,咱们发现深度学习没办法学到的特征大概能够分为两类:
对于一些数据的Pattern,在Train Data中出现的频数不足以让深度学习学到对应的特征,因此咱们须要经过手工提取这些特征
因为Deep Learning对样本作了独立同分布假设(iid),通常只能学习到每一个样本的特征,而学习到数据的全局特征,好比TF-IDF这一类须要统计全局词频才能获取的特征,所以也须要手工提取这些特征
传统的机器学习模型和深度学习模型之间也存在表达形式上的不一样。虽然传统模型的表现未必比深度学习好,但它们学到的Pattern可能不一样,经过Ensemble来取长补短,也能带来性能上的提高。所以,同时使用传统模型也是颇有必要的。
2.2 第一名的解决方案
比赛结束不久,第一名也放出了他们的解决方案,
咱们来看看他们的作法:https://www.kaggle.com/c/quora-question-pairs/discussion/34355
他们的特征总结为三个类别:
Embedding Feature
Text Mining Feature
Structural Feature(他们本身挖掘的Magic Feature)
而且他们也使用了Stacking的框架,而且使用固定的k-fold:
Stage1: 使用了Deep Learning,XGBoost,LightGBM,ExtraTree,Random Forest,KNN等300个模型
Stage2: 用了手工特征和第一层的预测和深度学习模型的隐藏层,而且训练了150个模型
Stage3: 使用了分别是带有L1和L2的两种线性模型
Stage4: 将第三层的结果加权平均
对比之后发现咱们没有作LDA、LSI等特征,而且N-gram的粒度没有那么细(他们用了8-gram),还有他们对Magic Feature的挖掘更加深刻。还有一点是他们Deep Learning模型设计更加合理,他们将筛选出来的手工特征也输入到深度学习模型当中,我以为这也是他们取得好效果的关键。由于显式地将手工特征输入给深度学习模型,至关于告诉“它你不用再学这些特征了,你去学其余的特征吧”,这样模型就能学到更多的语义信息。因此,咱们跟他们的差距仍是存在的。
3 工具篇
工欲善其事,必先利其器
Kaggle 的上常工具除了你们耳熟能详的XGBoost以外,这里要着重推荐的是一款由微软推出的LightGBM,此次比赛中咱们就用到了。LightGBM的用法与XGBoost类似,二者使用的区别是XGBoost调整的一个重要参数是树的高度,而LightGBM调整的则是叶子的数目。与XGBoost 相比, 在模型训练时速度快, 单模型的效果也略胜一筹。
调参也是一项重要工做,调参的工具主要是Hyperopt,它是一个使用搜索算法来优化目标的通用框架,目前实现了Random Search和Tree of Parzen Estimators (TPE)两个算法。
对于 Stacking,Kaggle 的一位名为Μαριος Μιχαηλιδης(https://www.kaggle.com/kazanova)的GrandMaster使用Java开发了一款集成了各类机器学习算法的工具包StackNet,听说在使用了它之后你的效果必定会比原来有所提高,值得一试。
如下总结了一些经常使用的工具:
Numpy | 必用的科学计算基础包,底层由C实现,计算速度快
Pandas | 提供了高性能、易用的数据结构及数据分析工具
NLTK | 天然语言工具包,集成了不少天然语言相关的算法和资源
Stanford CoreNLP | Stanford的天然语言工具包,能够经过NLTK调用
Gensim | 主题模型工具包,可用于训练词向量,读取预训练好的词向量
scikit-learn | 机器学习Python包 ,包含了大部分的机器学习算法
XGBoost/LightGBM | Gradient Boosting 算法的两种实现框架
PyTorch/TensorFlow/Keras | 经常使用的深度学习框架
StackNet | 准备好特征以后,能够直接使用的Stacking工具包
Hyperopt | 通用的优化框架,可用于调参
4 总结与建议
参加某个比赛前,要先衡量本身的机器资源可否足够支撑你完成比赛。好比一个有几万张图像的比赛,而你的显存只有2G,那很明显你是不适合参加这个比赛的。当你选择了一个比赛后,能够先“热热身”,稍微熟悉一下数据,粗略地跑出一些简单的模型,看看本身在榜上的排名,而后再去慢慢迭代。
Kaggle有许多大牛分享Kernel, 有许多Kernel有对于数据精辟的分析,以及一些baseline 模型, 对于初学者来讲是很好的入门资料。在打比赛的过程当中能够学习别人的分析方法,有利于培养本身数据嗅觉。甚至一些Kernel会给出一些data leak,会对于比赛提升排名有极大的帮助。
其次是Kaggle已经举办了不少比赛, 有些比赛有相似之处, 好比此次的Quora比赛就与以前的Home Depot Product Search Relevance(https://www.kaggle.com/c/home-depot-product-search-relevance)有类似之处,而以前的比赛前几名已经放出了比赛的idea甚至代码,这些均可以借鉴。
另外,要足够地重视Ensemble,此次咱们组的最终方案实现了paper " Ensemble Selection from Libraries of Models" 的想法,因此有些比赛可能还须要读一些paper,尤为对于深度学习相关的比赛,最新paper,最新模型的做用就举足轻重了。
并且,将比赛代码的流程自动化,是提升比赛效率的一个关键,可是每每初学者并不能很好地实现本身的自动化系统。个人建议是初学者不要急于构建自动化系统,当你基本完成整个比赛流程后,天然而然地就会在脑海中造成一个框架,这时候再去构建你的自动化系统会更加容易。
最后,也是最重要的因素之一就是时间的投入,对于此次比赛, 咱们投入了差很少三个多月,涉及到了对于各类可以想到的方案的尝试。尤为最后一个月,基本上天天除了睡觉以外的时间都在作比赛。因此要想在比赛中拿到好名次,时间的投入必不可少。另外对于国外一些介绍kaggle比赛的博客(好比官方博客)也须要了解学习,至少能够少走弯路,本文的结尾列出了一些参考文献,都值得细细研读。
最后的最后,请作好心理准备,这是一场持久战。由于比赛会给你带来压力,也许过了一晚,你的排名就会一落千丈。还有可能形成出现失落感,焦虑感,甚至失眠等症状。但请你相信,它会给你带来意想不到的惊喜,认真去作,你会以为这些都是值得的。
参考文献:
1.Paper: Ensemble Selection from Libraries of Models :http://link.zhihu.com/?target=http%3A//www.cs.cornell.edu/%7Ealexn/papers/shotgun.icml04.revised.rev2.pdf
2. Kaggle 数据挖掘比赛经验分享:https://zhuanlan.zhihu.com/p/26820998
3. Kaggle Ensembling Guide:http://link.zhihu.com/?target=https%3A//mlwave.com/kaggle-ensembling-guide/