关于第16名方案的几点说明
关于第16名方案的几点说明
作者:Silogram (Grandmaster) | 发布时间:2022-07-08
首先,感谢 Kaggle 和 Foursquare 提供了一个非常有趣的挑战。不过,数据泄露确实令人沮丧。这本该是一个很容易避免的泄露。我无法想象这是怎么漏掉的。寻找泄露是 Kaggle 比赛的常态,但当说明中明确指出不存在特定泄露时,它就不应该存在。
祝贺获胜者,特别是 @psi 后来居上并获得了获胜方案(如果我们不计算明确使用泄露的情况)。这是一场艰难的比赛,需要很多独创性才能取得好成绩。
我从这次比赛中最大的收获是:
- RAPIDS 是一个非常成熟且有用的库。这是我第一次使用 RAPIDS,我对几乎无需更改代码即可在 GPU 上运行如此多的 sklearn 和 pandas 功能印象深刻。加速效果非常显著,尤其是在非 GPU 版本仅使用 1 个 CPU 的情况下。还要感谢 @steubk 展示了如何使用 ForestInference 进行推理 (链接)。
- 老派 NLP 技术(如文本规范化、TF-IDF、关键词提取等)在特定情况下仍然适用。在本次比赛中,大部分文本是多种语言的名字,这降低了预训练文本模型的实用性。
- ML 工具集的成熟:随着机器学习工具集的成熟,ML 正越来越成为软件工程的一个专业领域。特别是在本次比赛中,正确设置问题以使用最少的资源分块处理数据,与所采用的具体 ML 算法同样重要。
关于本次比赛的一个大问题
为什么大多数顶尖团队来自日本?是数据的某些特点给了日本团队优势吗?
以下是我的方案简要概述(未明确使用泄露)。
训练流程
- 预处理训练数据:
- a) 规范化文本字段(小写、去除标点、规范化常见拼写变体、转换为 ASCII)。
- b) 选择频繁出现的名称关键词并编码为特征。
- c) 分离多个类别并将其编码为单个类别。
- 划分数据:按 point_of_interest 分组,将训练集随机分为两个相等的部分,生成两个集合——train0 和 train1。
- 分别处理这两个训练集:
- a. 获取文本字段的词频向量。
- b. 对于每个 id,按经纬度找出 200 个最近的邻居。
- c. 以 10 个邻居为一组生成特征(例如,第 1-10 个最近的邻居,然后是 11-20、21-30 等)。每个 id 与组内的 10 个邻居配对生成成对特征。总共生成了大约 50 个特征,其中最重要的包括:
- 文本字段之间的余弦相似度(特别是规范化后的名称、name_nonkey 和地址)。
- 距离排名(例如,第 2 近的邻居 vs 第 150 近的)。
- 前一个和后一个距离(例如,如果我们正在处理第 5 近的邻居,那么第 4 和第 6 个邻居的距离是多少)。
- 名称之间的 Jaccard 相似度。
- 原始经纬度。
- 编码后的类别。
- 配对中匹配名称词的数量。
- 最长名称的字符长度。
- 名称中字符的最小和最大序数值(字符集/语言的代理指标)。
- 类别匹配的数量。
- 编码后的国家。
- 训练浅层模型:同样以 10 个邻居为一组进行处理,训练浅层 LGB 模型来预测配对匹配。
- 筛选候选集:使用第 4 步的匹配预测来选择最可能的匹配。这里的目标是减少候选范围,并获得更平衡的训练集,同时不丢弃太多正样本。对于每 10 个最近邻居组,我们训练 2 个浅层 LightGBM 模型——一个用于 train0,一个用于 train1。我们使用一个集合的模型来预测另一个集合的匹配,从而获得两个集合的 OOF(袋外)预测。我们保存 40 个模型(20 组邻居,每组 2 个)用于推理。
- 设置阈值过滤:利用第 5 步的预测,我们设定阈值来过滤掉几乎没有机会匹配的候选者。我发现将阈值设定在约 30:1(正负样本比)效果很好。它捕获了约 95% 的正样本(在 200 个最近邻居对中的那些),同时消除了约 90% 的负样本。阈值