Datawhale AI夏令营——用户新增预测挑战赛
赛事链接:用户新增预测挑战赛。
赛事任务概述:「用户新增预测挑战赛」由科大讯飞主办,是二分类任务,需利用讯飞开放平台海量应用数据构建模型,预测用户是否为新增用户,评价指标为F1分数。其涉及知识点包括解决实际业务问题、掌握结构化数据处理流程、学习关键评估指标在二分类不平衡场景的应用、实践高级特征工程技巧以及掌握LightGBM模型和交叉验证的最佳实践。例如,通过分析用户行为数据来预测用户增长情况,优化产品迭代策略。
赛题及数据解读:赛题背景是通过分析讯飞开放平台用户行为数据预测用户新增,对行业和技术都有重要价值。输入数据有用户行为事件记录、15个原始特征字段,关键字段为udmap(JSON)和common_ts(时间戳),输出需预测用户是否为新增(is_new_did),提交格式为CSV文件。通过数据探索发现测试集中93%用户出现在训练集,训练集中88%用户is_new_did为0 ,为解题提供思路。同时可借助Pandas相关函数查看数据结构、缺失情况等。解题要点和难点包括将用户行为事件数据转化为用户级别预测、处理高维稀疏特征、应对正负样本不均衡等。比如,面对高维稀疏特征,需思考如何有效提取和利用这些特征来提升模型性能。
Baseline方案解析:Baseline仓库包含train.csv(含标签训练集)、testA_data.csv(无标签测试集)、Baseline.ipynb(全流程处理脚本)、submit.csv(预测结果提交文件)。其设计思路基于特征设计提取时间特征,模型选择LightGBM,采用五折交叉验证和基于F1 - score动态调整分类阈值。优点是避免数据泄露、计算高效,训练速度比XGBoost快3 - 5倍,但存在JSON字段未充分解析、缺乏特征筛选等待改进点。核心函数包括交叉验证建模,实现分层K折交叉验证流程;目标优化函数,寻找最大化F1分数的阈值。如在交叉验证建模中,通过将数据集划分为五个子集,每次选一个子集作为验证集,其余作为训练集,重复五次训练和验证过程,来稳定评估模型性能。
我这里对赛题任务数据和baseline做一个总结,具体内容大家可以去datawhale官网查看。
下面来介绍一下打这个比赛的感想吧,这里借用分享嘉宾Shimmer的标题:虚假繁荣之下。
主要就是数据泄露和交叉验证的问题,一定要揭开虚假的面纱,回归本真。
先上图,这是我第一次修改后的模型训练分数,直接干上了0.9以上:
上传A榜测试后也达到了0.8几的高分,突然的惊喜使我受宠若惊,顿时间让我感到了不祥的预感,于是我便细细分析代码,这里我觉得Shimmer的分享做的很好,(这里引用一下,在此再次感谢Shimmer的精彩分享):
这里baseline使用的是StratifiedKold,为后续埋下伏笔。
这里简单介绍一下三种常见的交叉验证方法:
KFold交叉验证:KFold是一种简单直接的交叉验证方式。它在划分数据时,直接随机地将数据分成k折。从“X = ["a", "b", "c", "d"],kf = KFold(n_splits=2)”可以看出,仅仅通过输入数据X就完成了划分,这个过程不受到数据标签class和我们人为给数据分组group的影响。这意味着在使用KFold时,无需考虑数据的类别分布或分组情况,它只是单纯地随机分割数据,这种方式适用于对数据分布没有特殊要求,仅需简单随机划分数据集的场景。
StratifiedKFold交叉验证:StratifiedKFold注重数据集的分布一致性。它在划分数据集时,会使得划分后的训练集和测试集的目标比例与原始数据集近似,也就是构造出分布相同的交叉验证集。例如“X = np.ones(10),y = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],skf = StratifiedKFold(n_splits=3)”,这里通过y给出了数据的类别分布,StratifiedKFold会根据这个分布来划分,保证每个折中的类别比例和原始数据相似。在一些数据类别分布不均衡的情况下,StratifiedKFold能更好地保留数据的分布特征,使得模型训练和评估更加准确。
GroupKFold交叉验证:GroupKFold适用于数据有分组的情况。当我们将数据进行分组后,GroupKFold能够保证同一个group的数据不会同时出现在训练集和测试集上。因为如果训练集中包含了每个group的部分样例,模型可能会对这些特定group的数据过度适应,在测试集上表现良好,但遇到新的group数据时就会表现很差。就像“X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10],y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"],groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3],gkf = GroupKFold(n_splits=3)”,这里通过groups明确了数据的分组,GroupKFold会按照规则进行划分,从而避免模型在不同group数据上的泛化问题,提高模型在不同分组数据上的适用性。
OK我们再回到数据本身:
1. 验证集污染:理想的验证集应该充满“陌生人”。但 `StratifiedKFold` 像洗牌一样,把同一个用户的记录切分到了训练和验证集里。“标准答案”的一部分被命题人提前给了考生,污染了考卷的纯洁性。
2. 目标泄露:做聚合特征(比如,“用户行为总次数”)的计算横跨了训练集和验证集。本应属于“未来”的信息,泄露给了“当下”,直接告诉了模型:介个用户不是新人。
这里我采用了以下方法:
- 使用GroupKFold: 按用户ID分组,避免同一用户的数据同时出现在训练和验证集。
- 修复目标编码: 使用平滑处理,避免数据泄露。
- 使用时序模型或混合模型:进行进一步优化处理,正确上分。
修改后回归本真,这里回到了0.6左右的分数,但是真实有效:
最后还是用Shimmer的结语作为结束:初出茅庐,对“过于美好”的分数保持一份怀疑。