1. 说明
这两天因为改赛制,改评测方法,钉钉群里说什么的都有,我也跟着焦虑,做了小一个月,虽然对自己的算法有点信心,但是强人也很多,不知能不能进复赛.复赛数据和目标都不一样,相当于一场新的比赛.
在赛前,比赛的第一周结束,第二周结束,各发过一篇:
《实战天池精准医疗大赛之一数据分析》
《实战天池精准医疗大赛之二再接再厉》
《实战天池精准医疗大赛之三_分类回归与排序》
本文是初赛的最后一篇,总结一下:最后阶段的算法集成;最终模型用到的所有具体算法;以及常见的坑.
2. 集成算法
数据从3到38不均衡分布,使用分类的情况下,不能确定边界划在哪里,最终使用多个边界,生成多个分类器,问题的难点在于,每个分类器的参数不同,比如:血糖小于5的,和血糖大于15的,比例差别很大,使用GBDT时,树的深度,节点权重需要分别调整,这里我使用了8个二分类器,做了一个自动调参的程序,调参的思想类似折半查找,以节省算力.
![](https://i-blog.csdnimg.cn/blog_migrate/3aa7f22f8ff2e6a2c76354908415b4b1.webp?x-image-process=image/format,png)
二分类器的目标都是切分"正常"与"异常",比如视15以上的为异常,15以下为正常,由于是二分类问题,可用scale_pos_weight设定正反例的权重,即使反例很少也能挑出来.
比较特别的地方是结合8个二分类器的结果,有一些分类结果可能是矛盾的,比如这个分类器预测血糖应该在10以上,那个分类器预测血糖应该在8以下.也试过线性回归等等算法,最后使用的是投票一致的结果,大概意思是,如果分类结果同时在7以上,8以上,9以上,12以上,才判断它在12以上.对于那些没法判断的,或者认为正常的,则使用回归的结果.
这个集成原理上应该算是stacking类的算法,即把前面模型的结果作为后面模型的输入.也有点像增补的方法,就是用回归提供基本预测,再用分类器筛出比较确定的高血糖,预测成更高的值.相当于人工改值变成了机器改值.
3. 具体实现
1) 特征工程
使用了比赛提供了30几个特征,除了把日期稍做调整,没加任何特征(也有人构造了上千个特征,而且提分了,但是我没用)。我做的唯一特征处理是标准化,另外训练之前去掉了一些完全不靠谱的属性,比如ID号等,之前的文章中介绍过。
2) 算法
最终使用的是xgboost,分类和回归使用的都是该工具.调用时使用了交叉验证,和技术圈中baseline的类似,回归用了10折,分类用了5折.
算法中比较特别的地方就是把回归改为了部分分类问题,但也带来一些新的问题,比如分界位置不对会把一簇数据切成两半;分类只能提高一定准确率,可能原来高血糖识别率是5%,用了分类后变成15%,但还有85%分辨不出来,分类后再做回归的话,还可能产生新的错误.
另外,在所有分类的评估和调参的过程中都使用了精确度precision替代auc(具体见文档:《医疗之三》),目的是找到确定的异常点,而不是让所有实例都正确分类.换言之,只关注"真正例"所占的比例,不管错的和不确定的点有多少.
由于分类器太多,写了自动调参程序,也有一些收获,比如,像max_depth等重要参数需要先稳定下来,再调其它;参数的取值范围不一样,有的变化步长是整数,有的是小数,还有范围,需要区别对待;还有特别重要的一点是,有的参数变化对结果的影响是线性的,有的是凸性,有的是多峰的,如果是线性或凸性的,可以用一些优化使调参更快,如果是多峰的,就需要用小的步长遍历整个取值范围.做好了调参程序,以后其它的数据挖掘也都省事儿了.
另外需要注意的还有,分类器对数据预测的分类结果是它属于某类的概率,二分类问题中就是一个0-1之间的小数.由于非均衡分类使用了scale_pos_weight参数,不能直接使用0.5作为分类的标准.解决该问题的方法是,如果正例占20%,则在预测结果中概率最高的20%认为是正例即可.另外,这些概率值也可以作为新的特征来使用,当然它与旧值会存在一些相关性.也可以将小数转成排序特征,这样也能比较清楚地看到它在所有实例中所处的位置.
4. 常见坑
1) 放弃了正确的方向
有时候本来选对了方向,但尝试后效果不好,于是放弃.到后来才发现,原来正确的方法一开始就想到了,就是没能坚持下来.可能也是因为一开始选择太多了,得有多大把握才能一条道走到黑,不去尝试其它?所以,可能需要在不同阶段再次尝试同一算法.
2) 不同的人使用同一算法,效果不同
在初始阶段,有时候调了半天算法,还不如baseline效果好,于是对baseline各种调参,但上分很少,还不如手动改几个重要值上分快,因此产生错觉:这还不如我用肉眼看呢?最后得出结论:机器学习就是不如人呀。
有时候钉钉上菜鸟听和大佬用同一算法,效果天差地别,所以像我这样的还需要多磨练.
3) 过拟合
有的参数直觉上没用,比如体验日期,序列号,明显和血糖高不高没关系,在训练集中加入后确实可以提分,却造成模型的过拟合,使线上得分下降。所以,觉得完全不辈谱,却能提分的,最好把它去掉。
4) 模块开发
有一次看一个天池答辩视频,讲组里人的分工,这个人做特征,那个人改算法,另一个人做集成,一开始不太明白,做前边步骤的人,怎么评价自己的工作质量。后来想这和调参一样,比如A->B->C三个步骤,我做B,那么就拿稳定的A和C模块,只改B部分,然后看评分变化。不过在一开始各个模块都频繁变化的情况下,确实挺难。我觉得组队可能还是主要各做各的,但是有一些头脑风暴和方法借鉴,或者是主要一个人带着另几个人做比较好一些。
5) 作弊与公平
这个比赛的讨论群特别热闹,一开始有人发现测试数据中有几个异常值对评分影响大,通过多次提交的对照能找出来,然后对结果数据手动改值,得到高分,一传十十传百,有个阶段不改值的人根本进不了排行榜。
这个问题的原因是数据量小.一共5000个数据,其中有十几个特殊数据,还能手动改,要是有5000万个数据,特征的十几万个,谁还能改?
另外,这和评价函数有关,常用的评价函数均方误差,均方根误差,基本都是累加每个实例误差的平方,比如有两个实例,一个误差是1,另一个是10,误差平方和是12+102=101,两个误差值差了10倍,但后一个误差对整体误差的贡献是前一误差的100倍,数越大越明显,于是有人问为什么不用绝对值,而用平方呢?这是因为平方更容易求导。
那什么样的实例误差最大呢?一般数据都是高斯分布,也就是数据集中地分布在均值附近,边缘较少,也就是不均衡分布。当使用一些迭代改进算法时,为正确预测大多数实例,模型的预测值会向均值收缩,这也就是为什么大家预测之后发现高血糖的比例明显减少了。也就是说高血糖被预测成了均值,误差会比较大.解决此类问题,可以给不同实例分配不同权重,把回归问题,先当分类问题处理等等。
什么算作弊?听人说改哪个实例算作弊?自已找出特殊实例就不算?手动改值算作弊机器改就不算?如果说能找出模型把血糖高的自动筛选出来,这题不就解了么?的确有人花了很多时间精力,由于别人作弊,开小号,而不能晋级,确实挺可惜的.但是,有的组人多,有的组人少,有人机器快,有人机器慢,本来就没有绝对的公平.
咱们也尽量佛系一点,毕竟进了复赛也进不了决赛,对吧.
顺便得瑟一下,进复赛了,哦耶!