返回列表

3rd Place Solution: EDA is the key

566. Playground Series - Season 3, Episode 19 | playground-series-s3e19

开始: 2023-07-11 结束: 2023-07-31 销量与需求预测 数据算法赛

第三名解决方案:EDA是关键

作者:Albert Zhang | 发布日期:2023-08-02 | 投票:13 | 排名:3

我很高兴在第一次参加Kaggle比赛就获得了第三名。之后我可能会写一个notebook分享细节,但要看情况而定。我想先阅读其他参赛者的解决方案。感谢@paddykb@kdmitrie以及所有贡献想法的朋友们。

EDA与数据处理

我认为EDA(探索性数据分析)是本次比赛最重要的环节,很可能也适用于大多数类似的比赛。

修正趋势

从每日总销售额的图表来看,2020年的趋势明显异常。我的修正方法如下:

  1. 计算75个类别各自的日销售占比
  2. 使用STL分解从日总销售额序列中提取趋势成分
  3. 将2020年2月15日至2020年11月15日的趋势替换为其他年份的平均趋势
  4. 还原日总销售额序列
  5. 根据各类别的占比还原各类别销售序列

基线建模

日总销售额的基线在每年似乎呈现离散状态。每个类别的基线可以建模为:

$$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为日期。

各类别日均值子图(标准化后)

按国家

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

按产品

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

按商店

所有商店的表现似乎相同。

汇总商店销售额

汇总商店销售额的原因:

  1. 根据以上分析,商店占比似乎恒定,且商店间的季节性和节假日效应没有差异
  2. 对于某些类别,例如《使用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探测确定。方法很简单:

  1. 随机猜测几个值并获得分数
  2. 用抛物线拟合
  3. 尝试最小值点
  4. 添加结果并重新拟合
  5. 重复3-4步一到两次

就是这样,希望能有所帮助。

同比赛其他方案