我很高兴在第一次参加Kaggle比赛就获得了第三名。之后我可能会写一个notebook分享细节,但要看情况而定。我想先阅读其他参赛者的解决方案。感谢@paddykb、@kdmitrie以及所有贡献想法的朋友们。
EDA与数据处理
我认为EDA(探索性数据分析)是本次比赛最重要的环节,很可能也适用于大多数类似的比赛。
修正趋势

从每日总销售额的图表来看,2020年的趋势明显异常。我的修正方法如下:
- 计算75个类别各自的日销售占比
- 使用STL分解从日总销售额序列中提取趋势成分
- 将2020年2月15日至2020年11月15日的趋势替换为其他年份的平均趋势
- 还原日总销售额序列
- 根据各类别的占比还原各类别销售序列
基线建模
日总销售额的基线在每年似乎呈现离散状态。每个类别的基线可以建模为:
$$B_{y, p, c, s} = B_y F_{y, p} F_{y, c} F_{y, s}$$
其中B表示基线水平,F表示占比,y为年份,p为产品,c为国家,s为商店。下标表示对应的组合类别。因此要找到2022年的基线,需要找出所有y=2022时的这些值。
按国家年份的占比

国家占比随时间波动。这些占比与人均GDP相关。但出于未知原因,2022年所有国家的占比都相同,均为0.2,可能是数据构造错误。
$$F_{y, c} = f_{y, c}; F_{2022, c} = 0.2$$
其中f表示经验占比,y = 2017, 2018 ... 2021。
按产品年份的占比

产品占比在各年份间基本保持稳定。似乎存在两年周期的季节性,但我更倾向于通过时间嵌入来捕捉。这里我将它们设为加权平均值:
$$F_{2022, p} = F_{y, p} = (2(f_{2017, p} + f_{2019, p} + f_{2021, p}) + 3(f_{2018, p} + f_{2020, p}))/12$$
按商店年份的占比

商店占比在各年份间似乎保持恒定,波动可忽略不计。
$$F_{2022, s} = F_{y, s} = f_{s}$$
日总销售额基线
我使用中位数作为基线。对于2022年,我暂时保持未知,最后通过LB探测确定。
$$B_y = median_y; B_{2022} \approx 18900$$
按类别进行EDA
标准化
使用基线模型,可以直接进行标准化:
$$S_{y, p, c, s, d} = N_{y, p, c, s, d} / F_{y, p} / F_{y, c} / F_{y, s} / B_y - 1$$
其中N为销售数量,S为标准化后的销售数量,d为日期。
各类别日均值子图(标准化后)
按国家

不同国家的节假日表现不同,尤其是日本。
按产品

不同产品的季节性不同。注意,虽然较弱,但有些产品具有两年周期而非一年周期的季节性。
按商店

所有商店的表现似乎相同。
汇总商店销售额
汇总商店销售额的原因:
- 根据以上分析,商店占比似乎恒定,且商店间的季节性和节假日效应没有差异
- 对于某些类别,例如《使用LLM赢得朋友和影响他人》-阿根廷-Kaggle Learn,销售量太小,在几个整数之间波动。这种序列可能影响模型训练

因此我使用按产品和国家的日销售总和进行训练和验证。应用类似的标准化:
$$S_{y, p, c, d} = N_{y, p, c, d} / F_{y, p} / F_{y, c} / B_y - 1$$
预测时,将此中间值转换回销售数量:
$$N_{y, p, c, s, d} = (S_{y, p, c, d} + 1) B_y F_{y, p} F_{y, c} F_{y, s} $$
我将所有模型参数放入Excel表格,见附件。
训练与预测
流水线
由于不同产品的季节性不同,我分别训练每个产品,因此有5个模型。训练数据按年份分为5折,进行交叉验证。
特征工程
由于私有评分基于2022年最后75%的数据,不需要滞后特征。
时间嵌入
- 对于周季节性,我使用最高3阶的傅里叶项
- 对于两年季节性,我使用最高5阶的傅里叶项
节假日和日期相关特征
我生成了两个分类特征:
- c_holiday:国家+对应节假日
- c_year_date:国家+一年中的365天
这些分类特征通过目标编码转换为数值水平。我使用线性混合模型,公式为S ~ 时间变量,按分类变量分组。当然,编码按产品分别进行。为避免过拟合,编码采用4~5折OOS预测。
参考:
https://www.statsmodels.org/stable/mixed_linear.html
https://arxiv.org/pdf/2104.00629.pdf
我没有进行特征选择。
建模
我使用LightGBM的线性树和DART模式。除了将`num_leaves`设为较小值(约5)外,我没有进行太多超参数调优。最优`num_iterations`由交叉验证RMSE决定。最终模型使用最优`num_iterations`在整个训练集上训练。我没有进行任何集成。
结果
验证SMAPE为4.87。
特征重要性:

如前所述,2022年日总销售额基线通过LB探测确定。方法很简单:
- 随机猜测几个值并获得分数
- 用抛物线拟合
- 尝试最小值点
- 添加结果并重新拟合
- 重复3-4步一到两次
就是这样,希望能有所帮助。