Recording︱有价值的各类AI、机器学习比赛心得、经验抄录

来源:互联网 发布:sql语句中case when 编辑:程序博客网 时间:2024/05/17 04:31

今年kaggle华人优胜团队很多,所以经验、心得不少,都是干货慢慢收集。

一、【干货】Kaggle 数据挖掘比赛经验分享

github:https://github.com/ChenglongChen/Kaggle_HomeDepot

1、了解数据分布

◆ 分析特征变量的分布
◇ 特征变量为连续值:如果为长尾分布并且考虑使用线性模型,可以对变量进行幂变换或者对数变换。
◇ 特征变量为离散值:观察每个离散值的频率分布,对于频次较低的特征,可以考虑统一编码为“其他”类别。
◆ 分析目标变量的分布
◇ 目标变量为连续值:查看其值域范围是否较大,如果较大,可以考虑对其进行对数变换,并以变换后的值作为新的目标变量进行建模(在这种情况下,需要对预测结果进行逆变换)。一般情况下,可以对连续变量进行Box-Cox变换。通过变换可以使得模型更好的优化,通常也会带来效果上的提升。
◇ 目标变量为离散值:如果数据分布不平衡,考虑是否需要上采样/下采样;如果目标变量在某个ID上面分布不平衡,在划分本地训练集和验证集的时候,需要考虑分层采样(Stratified Sampling)。
◆ 分析变量之间两两的分布和相关度
◇ 可以用于发现高相关和共线性的特征。

2、数据清洗

◆ 特征缺失值的处理
◇ 特征值为连续值:按不同的分布类型对缺失值进行补全:偏正态分布,使用均值代替,可以保持数据的均值;偏长尾分布,使用中值代替,避免受 outlier 的影响;
◇ 特征值为离散值:使用众数代替。
◆ 文本数据的清洗
◇ 在比赛当中,如果数据包含文本,往往需要进行大量的数据清洗工作。如去除HTML 标签,分词,拼写纠正, 同义词替换,去除停词,抽词干,数字和单位格式统一等。

3、特征工程

  • 特征变换

主要针对一些长尾分布的特征,需要进行幂变换或者对数变换,使得模型(LR或者DNN)能更好的优化。需要注意的是,Random Forest 和 GBDT 等模型对单调的函数变换不敏感。其原因在于树模型在求解分裂点的时候,只考虑排序分位点。

  • 特征编码

对于离散的类别特征,往往需要进行必要的特征转换/编码才能将其作为特征输入到模型中。常用的编码方式有 LabelEncoder,OneHotEncoder(sklearn里面的接口)。譬如对于”性别”这个特征(取值为男性和女性),使用这两种方式可以分别编码为{0,1}和{[1,0], [0,1]}。

对于取值较多(如几十万)的类别特征(ID特征),直接进行OneHotEncoder编码会导致特征矩阵非常巨大,影响模型效果。可以使用如下的方式进行处理:
◆ 统计每个取值在样本中出现的频率,取 Top N 的取值进行 One-hot 编码,剩下的类别分到“其他“类目下,其中 N 需要根据模型效果进行调优;
◆ 统计每个 ID 特征的一些统计量(譬如历史平均点击率,历史平均浏览率)等代替该 ID 取值作为特征,具体可以参考 Avazu 点击率预估比赛第二名的获奖方案;
◆ 参考 word2vec 的方式,将每个类别特征的取值映射到一个连续的向量,对这个向量进行初始化,跟模型一起训练。训练结束后,可以同时得到每个ID的Embedding。具体的使用方式,可以参考 Rossmann 销量预估竞赛第三名的获奖方案,https://github.com/entron/entity-embedding-rossmann。

对于 Random Forest 和 GBDT 等模型,如果类别特征存在较多的取值,可以直接使用 LabelEncoder 后的结果作为特征。

4、模型选择和验证

  • 对于稀疏型特征(如文本特征,One-hot的ID类特征),我们一般使用线性模型,譬如 Linear Regression 或者
    Logistic Regression。Random Forest 和 GBDT
    等树模型不太适用于稀疏的特征,但可以先对特征进行降维(如PCA,SVD/LSA等),再使用这些特征。稀疏特征直接输入 DNN 会导致网络
    weight 较多,不利于优化,也可以考虑先降维,或者对 ID 类特征使用 Embedding 的方式
  • ◆ 对于稠密型特征,推荐使用 XGBoost 进行建模,简单易用效果好;
  • ◆ 数据中既有稀疏特征,又有稠密特征,可以考虑使用线性模型对稀疏特征进行建模,将其输出与稠密特征一起再输入 XGBoost/DNN
    建模,具体可以参考2.5.2节 Stacking 部分

5、模型参数常规设置

DNN或者XGBoost中学习率这个参数,一般就选 0.01 左右就 OK 了(太大可能会导致优化算法错过最优化点,太小导致优化收敛过慢)
Random Forest,一般设定树的棵数范围为 100~200 就能有不错的效果,当然也有人固定数棵数为 500,然后只调整其他的超参数
.


二、阿里天池IJCAI17大赛第四名方案全解析(附代码)

github:https://github.com/Jessicamidi/Solution-to-IJCAI17-Sales-Volume-Prediction-on-Koubei-Platform
阿里天池IJCAI17:https://tianchi.aliyun.com/competition/introduction.htm?spm=5176.100067.5678.1.amifQx&raceId=231591

  • 赛题目标:通过阿里支付宝口碑平台2000个商户从2015.07.01到2016.10.31的商家数据,用户在支付宝端的支付和浏览日志,预测商家在未来14天(2016.11.01-2016.11.14)的客户流量。
  • 外部数据:天气数据(提供了世界各地在机场附近检测到的气象信息,包含气温,露点,湿度,气压,能见度,风速,瞬时风速,降水量,天气状况等信息。历史气象信息的采样间隔为30分钟。测试集首日,北京首都国际机场2016年11月1日气象条件)、节假日信息(节假日信息 HOLI.csv,将日期类型简单分为三个类别,其中工作日标签为0,周末标签为1,假期标签为2。)

1、数据清洗

数据清洗包含三部分,通过规则清除,通过模型预训练清除及仅保留销量统计信息。
规则清除:原始数据中,存在单用户某小时内大量购买的现象,如userID为9594359用户在2016年1月30日在shopID为878的商家累计购买了209次。针对此类现象,对于单个用户单小时内的购买数量x,采用以下公式处理消除异常消费
模型预训练清除:商家日销量,可能存在一些难以预计的大幅波动,如促销,商家停业等。对于这些规则难以清除的异常值,采用预训练的方式清除。

2、仅保留销量统计信息

由于只需要预测商家的日销量,无需识别单个用户的行为,按照大数定理,可以只针对分时段的浏览与购买总数进行预测。因而在数据清洗后,保留的数据仅按小时统计商户总销量,在这一步剔除了用户ID,使得数据量仅为原始的约1/10.

3、常规销量预测模型

3.1 特征与标签

这里写图片描述

3.2 训练方式

采用滑窗对于2000个商家日销量的时间序列生成481143条有效训练样本,清除间断前后及异常值后保留468535条样本。
采用2次训练的方法,第一次采用最大深度为3欠拟合模型进一步清洗脏数据。采用了xgboost与sklearn的GBDT模型训练,具体参数如下:
XGBoost-Round_1: 日销量仅作log处理,预训练后样本保留量为90%。
XGBoost-Round_2: 日销量仅作log处理后,采用过去三周的中位数作无量纲,预训练后样本保留量为75%。

4、 历史均值模型

输入:过去21天的历史销量,过去三周的销量相关度矩阵。
输出:未来2周的销量及其对应在模型融合中置信度。
方法:过去21天的按工作日平均,得到按工作日平均的均值销量。通过过去三周按周统计的销量中位数及平均值,做线性拟合得到销量增量。将历史均值销量叠加销量增量即得到未来2周预测销量。
由于方法本质上寻找历史上相似的(过去三周相关度较高)销量曲线作为未来预测,本质上为均值模型与KNN方法的结合。
置信度即为融合系数,仅当三周相关系数或后两周相关系数的最小值大于0.7时有效。均值模型的融合比例最大为0.75。

5、双11销量修正模型

模型概述:需要预测的时间段(11月1日到11月14日范围内)包含双11节日。从诸多商家的销量图上能明显看到在双11当天存在较大波动,可能的原因为网商促销对实体店的冲击,双11作为光棍节对于餐饮业的促进。然而仅有约1/3的商家存在2015年双11的销量记录,需要通过这部分商家去年双11信息,预测其余商家双11销量表现。
特征描述:仅包含商家特征,包含平均View/Pay比值,平均每天开店时间,关店时间,开店总时长;首次营业日期,非节假日销量中位数,节假日销量中位数,节假日/非节假日销量比值;商家类别,人均消费,评分,评论数,门店等级。

6、模型融合

多套gradient boosting的结果间的融合
xgboost1,xgboost2, GBDT三份结果按0.47, 0.34, 0.19 比例融合。
gradient boosting与均值模型融合
将均值模型结果与步骤1 gradient boosting 的结果融合,均值模型的融合系数为通过相关度得到的置信度。
双11系数进行销量调制
双11当天销量乘以双11销量修正模型得到的销量增量,11-12, 11-13由于为周六周日,有理由相信其销量与11-11(周五)的表现存在相似性, 因而乘以0.2及0.1倍的销量增量系数。
这里写图片描述

.


三、第一次参加Kaggle拿银总结——特征工程(FE)

截取特征工程部分,来源:http://scarletpan.github.io/summary-of-get-a-silver-medal-in-kaggle/
 在对一些基础的特征进行生成之后,我开始了漫长地测试特征的长征路,测试的思路我后来发现并不是很好,因为是通过新增加一个或几个feature,如果cv分数上去了,就增加这个feature,如果cv分数没有上去,就舍弃这个feature,也就是相当于贪心验证。这样做的弊处在于,如果之前被舍弃的feature和之后被舍弃的feature联合在一起才会有正面影响,就相当于你错过了两个比较好的feature。因此特征的选择和联合显得非常关键。

数值型feature的简单加减乘除

  这个乍一看仿佛没有道理可言,但是事实上却能挖掘出几个feature之间的内在联系,比如这场比赛中提供了bathrooms和bedrooms的数量,以及价格price,合租用户可能会更关心每个卧室的价格,即bathrooms / price,也会关心是不是每个房间都会有一个卫生间bathrooms / price,这些数值型feature之间通过算数的手段建立了联系,从而挖掘出了feature内部的一些价值,分数也就相应地上去了。

高势集类别(High Categorical)进行经验贝叶斯转换成数值feature

  什么是High Categorical的特征呢?一个简单的例子就是邮编,有100个城市就会有好几百个邮编,有些房子坐落在同一个邮编下面。很显然随着邮编的数量增多,如果用简单的one-hot编码显然效果不太好,因此有人就用一些统计学思想(经验贝叶斯)将这些类别数据进行一个map,得到的结果是数值数据。在这场比赛中有人分享了一篇paper里面就提到了具体的算法。详细就不仔细讲了,用了这个encoding之后,的确效果提升了很多。那么这场比赛中哪些数据可以进行这样的encoding呢,只要满足下面几点:1. 会重复,2. 根据相同的值分组会分出超过一定数量(比如100)的组。也就是说building_id, manager_id, street_address, display_address都能进行这样的encoding,而取舍就由最后的实验来决定了。

时间特征

  针对于时间数据来讲,提取年、月、日、星期等可能还是不够的,有另外一些points可以去思考,用户的兴趣跟发布时间的久远是否有关系?可以构造如下的feature来进行测试: python data[“latest”] = (data[“created”]- data[“created”].min()) python data[“passed”] = (data[“created”].max()- data[“created”])

  可以看到latest指的是从有数据开始到该房创建为止一共过去了多少时间,而passed则是该房记录创建为止到最后有记录的时候一共过去了多少时间。

  另外针对于时间特征还可以用可视化的方式来与其他特征建立联系,比如我们观察listing_id与时间变化到底有怎样的联系,能够绘制出如下的图来:
这里写图片描述

   可能简单的相除就能获得很好的结果

地理位置特征

  想到地理位置,就会想到聚类,一个简单的方式将每个房子划分到同一块区域中去;除了聚类以外,算出几个中心点坐标,计算曼哈顿距离或者欧式距离可能都会有神奇的效果。

文本特征

  实话说自己是看中这次比赛中有文本数据才参加的,因此在文本挖掘中做了很大的努力,比如提取关键词、情感分析、word embedding聚类之类都尝试过,但效果都不是很好, 对于文本的特征的建议还是去找出一些除了停用词以外的高频词汇,寻找与这个房屋分类问题的具体联系。

图片特征

  除了最后爆料出来的magic feature(后文会提到)以外,我只用了一个房子有几个照片这个信息。讨论区中都说对于图片特征用CNN提取、简单特征提取之类的效果都不是很好。

稀疏特征集

  其实就相当于一系列标签,不同标签的个数也是挺多的,本次比赛我只是简单地采用了counterEncoding的方式进行one-hot编码。值得一提的是,有些标签是可以合并的,比如cat allowed 和 dog allowed可以合并成为 pet allowed,我在这场比赛中手工地合并了一些feature数据,最终结果略微有所提升。

特征重要程度(feature importance)

  在树结构的分类器比如randomforest、xgboost中最后能够对每个特征在分类上面的重要程度进行一个评估。这时候如果已经选定了一些feature进行训练了之后,查看feature importance的反馈是非常重要的,比如本场比赛制胜的关键是运用manager_id这个feature,而它的feature importance反馈结果也是非常高。通过对重要特征的重新再提取特征,能够发现很多有意思的新特征,这才是用FE打好一场比赛的关键所在。

模型融合

  如果你没有idea了的话,就模型融合吧!模型融合是能够快速提高比赛成绩的捷径,现在的比赛几乎没有人不用到这个技巧,通常获胜者会对很多很多模型进行融合,并且会选择不同的模型融合的方式。这里有一篇非常好的模型融合解析 博文 ,相信每个看过它的人都会对模型融合有一个清楚的了解

  本次比赛中我使用了两种模型融合方式,一种是Averaging,一种是Stacking。

  先来说说Stacking,因为这场比赛一名贡献比较大的选手分享了一个叫StackNet的库,作为新手我就直接用了。首先我用我的xgboost cv集交叉预测出结果作为feature的一部分放到train data中,再对test data进行预测的结果作为feature的一部分放到test data中,再在第二层上选择了Logistic Classifer,GradientBoostingClassifer,AdaBoostClassifer,NNSoftemaxClassfier,RandomForestClassifer等进行交叉预测,第三层选取了一个randomForest作为最后的结果训练和预测。Stacking主要增多了模型的diversity,使我的成绩上升了至少0.003的量级,

  然后是Averaging,之前提到过Stacking需要交叉预测,我就选取了10组随机种子分别对训练集进行10-kfold交叉预测取平均,以及每个flod训练预测的时候我都对我的xgboost选取5个随机种子取平均。也就是说,在第一层Stacking的CV集交叉预测时我总共训练了500个模型进行平均。分数的提升大约在0.002左右。

  直到比赛结束看了排名靠前的选手的模型融合后,才发现自己对于模型融合只是做了一点微小的工作,提升空间还非常大。详情可以看FE部分分享的solution链接。
.


四、推荐|分分钟带你杀入Kaggle Top 1%

来源文章《推荐|分分钟带你杀入Kaggle Top 1%》

比较新奇的几个心得记录如下:
.

1、错误分析

人无完人,每个模型不可能都是完美的,它总会犯一些错误。为了解某个模型在犯什么错误,我们可以观察被模型误判的样本,总结它们的共同特征,我们就可以再训练一个效果更好的模型。这种做法有点像后面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)去掉,用剩余部分训练一个新的深度学习模型,相当于告诉模型看到这种情况的时候就不要判断为相似的了。因此,在加入这个特征后,我们的效果得到了一些提升。
.

2、特征工程

总结一下,我们抽取的手工特征可以分为以下4种:
Text Mining Feature,比如句子长度;两个句子的文本相似度,如N-gram的编辑距离,Jaccard距离等;两个句子共同的名词,动词,疑问词等。

Embedding Feature,预训练好的词向量相加求出句子向量,然后求两个句子向量的距离,比如余弦相似度、欧式距离等等。

Vector Space Feature,用TF-IDF矩阵来表示句子,求相似度。

Magic Feature,是Forum上一些选手通过思考数据集构造过程而发现的Feature,这种Feature往往与Label有强相关性,可以大大提高预测效果。
.

3、深度学习的不足与传统方法的优势

通过对深度学习产生的结果进行错误分析,并且参考论坛上别人的想法,我们发现深度学习没办法学到的特征大概可以分为两类:

对于一些数据的Pattern,在Train Data中出现的频数不足以让深度学习学到对应的特征,所以我们需要通过手工提取这些特征。

由于Deep Learning对样本做了独立同分布假设(iid),一般只能学习到每个样本的特征,而学习到数据的全局特征,比如TF-IDF这一类需要统计全局词频才能获取的特征,因此也需要手工提取这些特征。

传统的机器学习模型和深度学习模型之间也存在表达形式上的不同。虽然传统模型的表现未必比深度学习好,但它们学到的Pattern可能不同,通过Ensemble来取长补短,也能带来性能上的提升。因此,同时使用传统模型也是很有必要的。

.


五、多标签图像分类

来源:开发 | Kaggle亚马逊比赛冠军专访:利用标签相关性来处理分类问题

原文链接:Planet: Understanding the Amazon from Space, 1st Place Winner’s Interview

这是一个图像多标签预测的问题,来看看作者的模型:

这里写图片描述
精细调节了11个卷积神经网络(CNN),得到每个CNN的类别标签概率。比赛中我用到了一些流行的、高性能的CNN,例如ResNets、DenseNets、Inception和SimpleNet等。

再来看看作者 的模型集成:
这里写图片描述

可以看到11个模型出来的结果,并排,然后接一个ridge层,得到每个分类的最佳得分,从而确定最终分类。