返回列表

2nd place solution

390. M5 Forecasting - Accuracy | m5-forecasting-accuracy

开始: 2020-03-03 结束: 2020-06-30 销量与需求预测 数据算法赛
第二名解决方案

第二名解决方案

作者:Matthias
比赛排名:第 2 名

各位 Kaggle 友好!

首先,我要感谢 Makridakis 教授、Evangelos Spiliotis、组织团队、慷慨的赞助商以及所有参与举办这场有趣比赛的相关人员。

我还要感谢所有伟大的公共 Kernel 贡献者,他们为我的解决方案和最终排名奠定了基础。没有你们的出色工作,这一切都不可能实现!(请参阅总结末尾的致谢)

1. 在我们开始之前...

整体方法由分组层次结构顶部和底部的两个独立建模流组成,它们通过对齐来获得结果。该方法对于任何给定的时间范围都应是可重现的,并且可以自动化,因此对于任何复杂的分组/层次时间序列问题都很有价值。

2. 起点

为了快速提醒我们的基线是什么,查看这个 Notebook 会很有帮助。很明显,如果我们不能显著击败 0.75,那我们就走错路了。

3. 底层 LGB 模型 - 单个商品被购买的“概率”:

底层基于许多参与者使用的 LGB 模型。(感谢 @kyakovlev - 感谢您在这次挑战中的出色投入)

一个非常重要的方面是,我没有使用任何历史销售数据作为特征(没有滚动均值,没有滞后,没有上次购买等)。

我的假设是,WI_1 商店中购买薄荷糖的驱动因素不是昨天买了一次、周一买了两次,而是价格、日期时间、SNAP(食品援助计划)等。

LGB 模型基于外部驱动因素学习每个商品(数量)在给定商店、给定日期被购买的“概率”。(顺便说一句——向所有阅读我在这里疯狂想法的统计学家致歉

深入理解这些底层模型将是下一步的重要工作。例如:为什么聚合时误差会如此完美地相互抵消?(我有一个理论,但现在写出来太令人尴尬了——测试后会跟进)

也许我的假设最终被证明是完全错误的,但在经验上,它们在这个给定的数据集上是站得住脚的。

作为旁注:学习率 0.2,3600 次迭代……这个模型的设置非常基础。按商店进行训练。

4.) 正确水平的问题

当遵循这种底层方法时,我们遇到了一个问题。生成的模型不包含任何趋势或季节性。(请参阅评论讨论——这一点是不正确的)

由于其间歇性,我们无法(或者至少我无法)对基础信号进行“去趋势”处理。

也许加入某种滚动/滞后数据可能行得通——但我没有看到一种稳定的方法来实现这一点,既让我能理解或至少相信我理解(有时这并不是一回事:-)),又能让我控制。

这次比赛中很多人选择用“魔法乘数”来解决这个问题。

我用来上下移动水平的是论坛中讨论的自定义损失函数之一

def custom_asymmetric_train(ypred, ytrue):
    y_true = y_true.get_label()
    residual = (y_true - y_pred).astype("float")
    grad = np.where(residual < 0, -2 * residual, -2 * residual * multiplier)
    hess = np.where(residual < 0, 2, 2 * multiplier)
    return grad, hess

当乘数 > 1 时,我们可以训练模型“超调”真实值;当乘数 < 1 时,我们训练模型“欠调”真实值。我认为损失函数的方法比用乘数移动结果效果更好,但我没有比较这两种方法。

顶层聚合的良好拟合和超调拟合如下所示:

同比赛其他方案