记第一次Kaggle比赛--Allstate Claims Severity

来源:互联网 发布:linux 查看进程内存 编辑:程序博客网 时间:2024/05/21 22:21

  第一次接触Kaggle是想找一些图像分类的题目,捣鼓下CNN,不过实验室连块好显卡都没,深一点的网络就没法训练了。后来看到个关于预测科比投篮命中的题目,感觉很有意思,最近参加了第一次比赛Allstate Claims Severity,最后排名168/3055top6%,有一块bronze medal.
  Allstate Claims Severity是个回归问题,要求预测Claims Cost。说实话我对金融一无所知,不过给的训练数据的特征是匿名的,总共130维的特征,其中14维是numeric feature,剩下的都是category feature。
  听别人讲Kaggle就是feature engineering + tuning + ensemble,其中关键在于feature engineering。说来惭愧,这次没怎么花时间在特征上,其实就是不会弄,主要就在调参和ensemble了,之后有空要好好学点这方面的知识。Kaggle的Kernel和Forum都很活跃,很多人都愿意分享自己写的脚本,讨论比赛相关的问题,很感谢他们的分享,对于我这种初学者来说真是受益匪浅。

关于特征

  关于特征的话我基本参考了Kernel中比较流行的做法,对于numeric feature检查它的偏度(skewness),超过一定阈值的特征做box-cox变换,利用scipy库能很方便地实现

skew_feats = train[numeric_feats].apply(lambda x:skew(x.dropna()))skew_feats = skew_feats[skew_feats > 0.25]skew_feats = skew_feats.indexprint skew_featsfor f in skew_feats:    train_test[f] = train_test[f] + 1    train_test[f], lam = boxcox(train_test[f])

  之后对所有的numeric feature都做数据标准化(StandardScaler),也就是减去均值后再除以方差。
  对于目标值loss,其分布不均,用log变换能有所改善,直接log(loss)的话,其值分布在比较小的时候仍然会有些起伏,因此往往会对loss加上偏移shift后再做log变换,关于shift社区里也有一些讨论,比如这里。
  
  对于category feature,常见的做法是转换为dummy matrix,见下图,pandas有直接转换的api。

ori dummy matrix c_feat1 c_feat1_A c_feat1_B c_feat1_C A 1 0 0 B 0 1 0 C 0 0 1

 
  还有一种做法是将直接根据类别赋相应的值,比如A~B对应1~26,有多个字母就逐个累加。

c_feat1 c_feat1_ A 1 B 2 C 3

 
  社区里有人质疑这样会让分类器误认为该特征之间有线性关系,但也有人说能够证明这样与dummy matrix等价。我没有深入去看,至少这种方法占内存少,在xgboost中表现很不错。
  另外category feature中有部分特征分布及其不均匀,对预测的贡献有限。可以对重要性较高的特征做组合,这里的重要性可以参考Linear Regression或者Random Forest得到的重要性。

模型

  模型主要就用了xgboost和Neural Network两种,两者单个模型的表现都不错,其他的模型可能加入ensemble会有帮助,我没来得及研究了。(社区中有提到Genetic Programming也有很好的单个模型表现,另外有看到比赛结束后前几名的方法分享,有人也几乎只用了xgboost和NN。)
  xgboost的输入对category feature用了第二种方式处理,加上了特征组合。dummy matrix的特征数更多,台式机的内存才4G,实在是塞不下了:( 。另外我发现笔记本i5的CPU居然算得还没破台式i3的快,看来还是桌面级的给力啊:(
  训练的时候一定要做交叉验证,并且记得保存oob的预测值,之后ensemble会用到。预测时可以用kFolds训练得到的k个模型各进行一次预测,最后取平均;也可以最后在所有训练数据集上重新训练一个模型来预测。前者的分数要更高些。

  Neural Network用的keras库,theano做backend。结构即普通的全连接网络,每一层加Batch Normalization,激活函数用ReLU。
  特征这里用了dummy matrix,测试下来效果要比第二种方法好。不过也许把用第二种特征训练的NN加入ensemble会有帮助,最后给忘记了。theano用了笔记本的GPU感觉算得也不是很快,最后扔给台式CPU去算了。调参的话可以借助hyperopt包,贝叶斯优化的原理有空要记的看下。另外这里还对交叉验证中每个fold的NN做了一个n次平均,事实证明对结果很有帮助。

ensemble

  上面xgboost中已经用到了boosting,另外每个fold的模型取平均也类似于bagging,这其实都是在做ensemble,最后对单个模型做ensemble也很重要。我加入ensemble的模型不多,一共8个,主要很多模型效果不好,另外训练太耗时了。
  
  模型少的话常用weighted average,也就是加权平均。每个模型占的权重可以用优化问题来求解,使加权后的loss对应的平均绝对误差最小,scipy有对应优化包。
  另外在社区中看到有用蒙特卡洛方法(Markov Chain Monte Carlo)来求权重,看了下代码是通过随机方向来优化权重,测试结果稍好于求解优化问题,速度也要更快。
  比赛结束后也有人分享优化权重的方法,该方法也只用了少量模型,效果很好。
  
  还有种ensemble的方式叫stacking,这里需要用到之前训练保存的oob预测值。
  stacking
  
  假设训练数据分成5份,每次训练取4份,剩下1份验证,那么用4份数据训练得到的模型就能得到1份的预测值。这样循环5次就能得到所有训练数据的oob预测值,stacking就是用这些预测值作为输入,训练数据真实的loss作为目标值,训练第二层的模型。最后用之前测试数据的预测值作为输入,来得到最终的预测值。
  遗憾的是我尝试了Linear Regression、Ridge、Lasso、Elasticnet、NN、xgboost,stacking 的效果都不如weighted average。一个可能是我第一层的模型太少了,也可能是模型间的相关性太高了。但社区中有人用stacking得到了很好的效果。

  最后除了LeaderBoard的分数,也要看重本地cross validation的得分,我最后就对LB有点过拟合了。总得来说在这次学到了不少东西,挺喜欢kaggle社区的氛围,从大家的分享中能学到很多数据和机器学习相关的知识和技巧,之后要继续努力了。

0 0