研二上学期已步入尾声,回首望去,知乎看山杯可以说是我这学期的主线了,历经近四个月的赛程,今天早上8点封榜,名次是12/706。
目录
三 阶段2:0.76开源 lgb+特征工程 继续踩坑(各种leak)
一 比赛简介
前排大佬tql。。。A榜第9、B榜登顶的test大佬、kaggle master chizhu大佬、鱼佬。【lpl总冠军】也是破邮的队伍,其中Clitost是2019搜狐算法大赛的冠军(emmm我这个菜鸡又拉低破邮平均水平了)。
二 阶段1 自己摸着石头过河 尽情踩坑
感谢学长提供的服务器 20C40T的E5 + 128G内存 + 2*TITAN Xp 要不然这比赛的数据量根本没法做o(╥﹏╥)o
1 数据预处理
比赛8月底开始 那必然是先分析数据了 和学长先做了一波预处理、清洗 从原始数据集中提取类别特征、序列特征、做表连接来得到训练数据等 当时还没怎么接触过pandas 用dict来手动做表连接 那可真是出力费时又不好用 还有 把原始的长id转换成短id 这个其实用sklearn.preprocessing.LabelEncoder一行就可以搞定 可惜当时不知道。。。
原始数据集有很多问题 比如有5个字段是废弃的 再比如官方说user表和question表中 包含了invite表和answer表中涉及的所有u/q 但官方放出的初版数据并不符合这一点 有很多uid在user中找不到 所以当时是做了一波过滤 然后模型训练/预测也要特判 挺麻烦的 耽误了不少时间 不过官方9月底更新了数据
2 数据分析
验证集(官方叫验证集,即a榜测试集)和训练集用户的交集:
验证集的冷启动用户并不多 约10%
验证集和训练集问题的交集:
但验证集冷启动问题很多 占比为2/3
变长序列特征(文本/话题等)的长度分布 最多100 当时做这个主要是为了设nn模型里的max_len
用户关注话题数量的分布
用户感兴趣的话题数量的分布 最多10(感兴趣的话题是知乎用户画像团队预测出来的 而关注的话题是用户实际关注的)
问题所属话题数量的分布 最多15
问题标题长度(单字)分布
问题标题长度(词)分布
问题描述文本长度(单字)
问题描述文本长度(词)
问题已有回答数量
答案文本长度(单字)
答案文本长度(词)
特征
当时自己不了解比赛的套路 以为跟论文一样 高下之分就在模型结构 只用了原始特征 uid qid topicid/wordid序列 验证集划分也就是分出0.2的作为验证集(不考虑时间当然是要leak 效果就)
模型
当时不了解比赛/工业界 只是通过看论文了解算法 所以当然不知道什么xgb/lgb 先试了一手ncf 只用uid/qid的线上auc是0.59 关于序列特征 尝试了各种模型(以bigru+att为代表)、各种网络里拼接/点乘的操作 不管是用官方预训练embedding 还是随机初始化来训练 都不能起到正向效果 很烦 然后使用deepctr库跑了很多个模型 收敛后logloss还是很高 各种过拟合 各种调参 最好的成绩是不使用预训练词向量的deepfm 0.68
就很烦 使出浑身解数 怎么也上不去分 (当然 自己那时候就是找错了方向)
三 阶段2:0.76开源 lgb+特征工程 继续踩坑(各种leak)
10月中旬 刘康大佬公布了一个0.76分的baseline 学习一波 才发现 大佬用pandas做的的数据预处理那么简洁 原来要做各种统计特征(尤其是count特征 算是利用了召回阶段的工作 因为对一个用户推送的越多 说明该用户更有可能产生点击行为 【广告主或者线上推荐系统,一定会朝着转化率高的属性加大投放】)上分效果这么明显 lgb这模型真是太稳定了(dev效果稳定增长、线上线下的差距不会有大幅波动) 于是重构代码 学习用pandas做各种处理 join/merge progress_apply+lambda等各种方便的操作 但缺点也很明显 就是太慢了 无法充分利用多核cpu 尝试了用multiprocessing/joblib来并行加速 然而效果并不理想 有时候多核反而更慢了==
首先是自己绞尽脑汁构造特征 很快发现性价比很低 于是开始参考之前各种ctr比赛的top方案来做特征 参考了林有夕、鱼佬、郭大他们的开源 但效果甚微 很多次以为自己发现了强特 激动不已 线下成绩却惨不忍睹大 很困惑 后来了解到是因为leak 但关于如何妥善的划分验证集 还是不太清楚 自己尝试了很多划分方案 例如把邀请表按周划分 但answer表仍然会导致leak 尝试一些划分 时空复杂度很大 尝试了各种特征 也用了五折交叉验证 但结果不尽如人意 这个阶段还是没能顺利上分
四 阶段3:0.8开源 解决特征穿越
11月底 刘泽大佬公布了0.8的baseline 主要从中学习了invite/answer划分的方式 来避免特征穿越导致的leak
每一天的答案创建数量 周末这两天明显更少 可能大家都是工作日摸鱼刷知乎?(误)
可以根据day得到week_id、判断该天是否是周末等 不过用了这些信息似乎并没有太大作用
官方是把553周的数据分为两半 用作a/b榜的测试集
线下将552周作为测试集 可以用来验证特征是否有效 就不需要太多次的线上提交来验证了 也可以避免过拟合a榜测试集 这样来筛选特征就比较可靠了 验证方式如图:
线下预测552周时 训练只用了一周的邀请数据 尝试过使用全量历史邀请数据 但是效果更差 不知道为什么 但毕竟涉及answer_info的统计特征是用了所有552周起始时间之前的 所以也算考虑了历史信息
模型主要用的是lgb 找了3套祖传参数 xgb效果比lgb低了两个百 但两者融合能有4个千的提升 试了deepfm/deepfm/lr 比lgb差得远 由于时间比较紧(12月初才搞清楚正确的验证集划分方式) 没有在模型融合上做太多功夫(没有用stacking之类的)
特征。其实我讲特征的意义不大,肯定不如答辩时前排大佬们的特征,不过自己也算是做了很多尝试。做特征还是很难的,听前排大佬讲的时候觉得这些特征倒也不是说有多复杂,但自己做的时候就是想不起来。可能就是【一看就会,一写就废】吧哈哈哈
加的特征倒也不多 虽然参考了很多之前的ctr top方案,但在这次比赛里有效的其实挺少的主要的强特是林有夕在科大讯飞里用的id+hour的count 但这个强特有效的前提是 训练和预测的数据量要保持一致 例如训练时可以只用半周的数据 因为线上测试集是只有半周 如果用整周的统计特征来训练 去预测半周的测试集 那就不合理所以效果很差
这个很多前排大佬都考虑到了(否则会错过很多强特) 例如MemoryError队对数据量不一致的处理方法:
lpl总冠军队的处理方法:
后期也拉了一个模式识别实验室做nlp的大佬 用各种模型做了一些文本特征 主要思路是算u/q两侧的文本相似度 提升还是有的 只是不如统计特征的提升大 就不多说了
五 总结
1 收获
(1)第一次使用lgb/xgb
(2)第一次做特征
深切体会到了比赛与科研的不同,平时看的论文里各种花里胡哨的模型,在比赛里用处并不大;而找到一个强特征,则能飞速上分。 count ratio ctr cvr
引用林有夕林大佬在开源代码中的赠言:
良好的阶段性收获是坚持的重要动力之一
2 不足
(1)代码复用性差
代码写的乱,构造特征流程繁琐,应该封装为模块,方便后续使用,否则会耽误大量时间。
(2)实验记录乱
特征、参数的对比实验太多 很乱
(2)不够严谨
根据之前线下验证的结果,lgb和xgb均值融合会有两个千的提升,于是昨晚睡前运行了xgb 5折的代码(因为全量数据xgb速度很慢),准备早起融合一波。但是由于没有仔细考虑代码,导致使用xgb跑五折时在夜里运行过程中出错,无法超越第11名。
不过没有关系,反正超越了也没什么意义,前十的队伍可以受邀去颁奖现场,那么11和12并没什么差别,何况我跟第10名的差距还是挺大的(6个千)。
上天对我还算仁慈,让我是12名。要是前面少一个队,我就差这么一丢丢分数就能到第10名,那就太可惜了,自己必然又是一番【意难平】。
不过后来咨询主办方,没有进前十的队伍也可以去现场旁听,那倒损失不太大,可以去学习一波。
(3)心态
- 比赛历时近四个月(中间还延长了一次),导致战线拉得很长,在尝试各种特征上分无望后,后期明显动力不足。
- 从大学时的蓝桥杯、去年的知乎用户行为预测比赛、暑期的研创比赛,到这次看山杯,发现自己心态特别差。这些比赛是自己用心去做了的,投入很多,但是结果却不尽人意,挫败感油然而生,以后就不愿再碰这些东西。正如安妮宝贝的句子:
仿佛是蜕下来的旧壳,余留着创口的血液热气和温度,只有自己能够看见。换上新躯壳的人,对它们有一种羞耻之心。也无留恋。