559. GoDaddy - Microbusiness Density Forecasting | godaddy-microbusiness-density-forecasting
最新:我已上传获得奖金分配所需的正式模型提交文件:https://www.kaggle.com/competitions/godaddy-microbusiness-density-forecasting/discussion/425000
代码地址 - https://www.kaggleqrdl/first-place-code,下方有详细解释。
首先我要感谢Kaggle、Venture Forward团队和GoDaddy。不仅感谢他们创建了Kaggle平台、主办这场比赛并提供小微企业数据——这些 truly 是令人难以置信的信念之举——还要感谢他们对我坚持透明度的耐心。我是一名彻底的平均主义者,坚信透明度是我们实现这一目标的途径。
本次比赛的目标是预测2023年3月、4月、5月(分别提前3、4、5个月)美国3135个县的小微企业密度。这里的小微企业密度大致等于GoDaddy注册域名数量除以该县成年人口(以美国人口普查2年滞后数据为准)。
例如:如果2023年2月,密苏里州德卡尔布共有10个GoDaddy域名注册,根据2021年人口普查该县成年人口为200人,那么该月该县的小微企业密度将增加10/200,即0.05。
我们获得了2019年8月至2022年12月的历史小微企业数据进行训练,以及一个用于验证1月数据的"公开排行榜"数据。Kaggle提供了公开排行榜的得分,我们每天可以提交5次结果。
为了赢得比赛,我基于过度拟合1月公开排行榜的策略建立了基线预测,并使用线性回归将其预测扩展到3月、4月和5月。
'sklearn.linear_model.LinearRegression', ['pct_college_2021', 'l11_uemp', 'shiftf1_l1_active'] - 4个月提前预测
'sklearn.linear_model.LinearRegression', ['shiftf1_l1_active_logit', 'pct_college_2019', 'l4_active','l10_lf'] - 3个月提前预测
'sklearn.linear_model.LinearRegression', ['l8_uemp', 'l1_ur', 'l11_uemp', 'l10_ur', 'pct_bb_2017'] - 2个月提前预测
我通过在最后一个可能的窗口(分别为2、3、4个月)进行交叉验证且不重叠的方式选择了这些特征。
似乎有帮助的核心思想:
*sklearn中的每个回归模型、各种arima库(我在这里花了很多时间,感觉是浪费的)、分层模型、xgb、catboost、lgbm、pytorch/dll。我不仅手动调整了上述模型,还尝试了各种自动方法,如网格搜索/optuna。有很多非常令人兴奋的结果,但最终我意识到自己可能只是在过拟合。
值得注意的是,我从公开排行榜到私人排行榜对第2和第3名的领先优势显著增加。我认为这是由于我对4月/5月的预测更优,因为我的3月结果有些差强人意。我对前20名的领先优势也有所增加,尽管不太清楚公开排行榜对他们的模型影响有多大。
我也尝试了许多不同的数据集(包括我公开分享的所有数据),甚至包括"godaddy"的谷歌关键词趋势。上述方法结合早停效果最佳。使用其他特征时偶尔会出现良好的CV分数,但添加它们经常感觉像过拟合。
我 briefly 研究过使用zone文件和whois数据库,但这些并非公开可用,所以我当然没有使用它们。
从理论上讲,爬取/抓取会是公开数据,但我已承诺自己不使用任何未公开分享的数据,因此我认为这并不值得付出所需努力。
我使用的所有数据都分享在我比赛开始时制作的数据集中。
我在各县单独模型方面做了很多初步工作,最终认为这是浪费的。几乎没有足够数据来验证上述模型和特征。或许有办法对各县进行分离,问题是——你是否也必须分离训练数据?增加的复杂性是否值得可能只是渐进式的改进?很难说,特别是当你的CV分数如此不稳定时,观察渐进式改进几乎是不可能的。
我花时间研究过各县之间的相关性。我认为可以论证不同的县可能以潜在的滞后时间遵循相似的趋势。这里可能还有更多可挖掘的,但需要全局性地完成,而不是单独进行,且你的模型需要适当的数据充分性。
另一个我没有仔细研究的特征是GoDaddy域名的1/2/3年等年度续费,这是最近在与一些域名转售商在域名转售社区论坛聊天时获得的想法。我怀疑他们会提供更多围绕此可加以利用的想法。
正如我上面提到的,其他人也提到过,数据是非稳态的,除了一些全局线性增长系数。也有人说较小的县增加了很多噪音,但我认为是正确的,试图看看我们能否在那里做些什么。农村地区周围的统计数据和分析存在缺乏,紧急问题很难被发现。
看待数据的另一种方式可能是波动性而非方向。活跃域名的剧烈波动可能只是由于数据错误,但也可能是由于潜在的社会和经济因素。在后一种情况下,我们需要考虑:波动性是否可能是一种机会,像火花的首次迸发?这些县能否从更有针对性和适时的投资中受益?如果波动性县具有更大潜力,那么波动性的触发因素是什么?这些是值得考虑的问题和实验(信号+干预)。
如果VF团队想联系我(笑),欢迎随时联系。你可能已经注意到,我可以整天和同样感兴趣的人谈论这些东西。
..
团队更新中存在一个bug,我无法更改我原本指向下方消息的排行榜指针,所以你们只能同时看到两个。我原本更感兴趣其他人做了什么,因为我对上述简单方法并不太乐观。回想起来,我本应该更相信我的排除过程。
之前的帖子标题:你对3月/4月/5月相对12月的平均活跃变化是多少?
编辑 - 首先明确说明,你可以通过执行此代码分享你的提交结果。它使用小微企业密度而非活跃用户,但这应该适合比较。
dfc = pd.read_csv("submission.csv")
rt = pd.read_csv("revealed_test.csv").set_index("row_id")
dfc['first_day_of_month'] = dfc['row_id'].apply(lambda x:x[-10:])
dfc['cfips'] = dfc['row_id'].apply(lambda x:int(x[:x.index("_")]))
dfc = dfc.reset_index().set_index("row_id")
dfc['mbd_chg'] = dfc.apply(lambda r:(r['microbusiness_density'] - rt.loc[f"{r['cfips']}_2022-12-01", 'microbusiness_density'])/rt.loc[f"{r['cfips']}_2022-12-01", 'microbusiness_density'], axis = 1)
display(dfc.groupby("first_day_of_month").mean()['mbd_chg'])
....
我们还需要一段时间才能获得最终结果,我认为5月的结果可能在决定最终获胜者方面发挥重要作用。在等待期间,分享我们实际预测的内容可能会很有趣。我们可以比较实际结果,这很好,我已将我的两个结果上传 - 但对于那些不想下载文件的人来说,或许更简单的方法是分享相对活跃用户的平均百分比变化。
这是我使用的代码。它需要你的数据框中12月的准确值,并且需要计算'active'作为其中一列。
如果你不想使用活跃用户,也可以使用小微企业密度,但我发现由于人口变动,它不那么有趣。人口变动中存在一些异常值,使得更难确保不会出错,所以我喜欢有活跃用户可用。下面我同时分享了两种方法。
你可以使用此代码计算cfips/首日:
dfc['first_day_of_month'] = dfc['row_id'].apply(lambda x:x[-10:])
dfc['cfips'] = dfc['row_id'].apply(lambda x:int(x[:x.index("_")]))
使用此代码计算active_chg值:
dfc = dfc.reset_index().set_index("row_id")
dfc['active_chg'] = dfc.apply(lambda r:(r['active'] - dfc.loc[f"{r['cfips']}_2022-12-01", 'active'])/dfc.loc[f"{r['cfips']}_2022-12-01", 'active'], axis = 1)
dfc.groupby("first_day_of_month").mean()['active_chg']
这是我的季节性模型
first_day_of_month
2022-11-01 -0.00635502
2022-12-01 0.00000000
2023-01-01 0.00328686
2023-02-01 0.00328686
2023-03-01 0.01505438
2023-04-01 0.02265933
2023-05-01 0.02476927
Name: active_chg, dtype: float64
这是我的长期趋势模型
first_day_of_month
2022-11-01 -0.00635502
2022-12-01 0.00000000
2023-01-01 0.00328686
2023-02-01 0.00328686
2023-03-01 0.00881651
2023-04-01 0.01215006
2023-05-01 0.01580625
Name: active_chg, dtype: float64
如果你没有活跃用户列,使用mbd代码:
dfc = dfc.reset_index().set_index("row_id")
dfc['mbd_chg'] = dfc.apply(lambda r:(r['microbusiness_density'] - dfc.loc[f"{r['cfips']}_2022-12-01", 'microbusiness_density'])/dfc.loc[f"{r['cfips']}_2022-12-01", 'microbusiness_density'], axis = 1)
dfc.groupby("first_day_of_month").mean()['mbd_chg']
季节性提交
first_day_of_month
2022-11-01 -0.00635502
2022-12-01 0.00000000
2023-01-01 0.01208731
2023-02-01 0.01208731
2023-03-01 0.02388208
2023-04-01 0.03161783
2023-05-01 0.03375395
Name: mbd_chg, dtype: float64
长期趋势提交
first_day_of_month
2022-11-01 -0.00635502
2022-12-01 0.00000000
2023-01-01 0.01208731
2023-02-01 0.01208731
2023-03-01 0.01764007
2023-04-01 0.02099663
2023-05-01 0.02467693
Name: mbd_chg, dtype: float64
注意:对于2月,我直接使用了1月的数值。分享1月数据当然不是那么有帮助,我只是在这里为了好玩而已。