559. GoDaddy - Microbusiness Density Forecasting | godaddy-microbusiness-density-forecasting
本次竞赛的目标是预测美国所有县每月的小型企业域名注册数量除以活跃人口的结果。与其他时间序列竞赛最大的不同在于:公开排行榜仅评估1个月后的预测分数(1月份),而最终评分将基于3-5个月后的数据(3月、4月、5月)。我原本预期需要处理各种宏观经济解释变量,甚至可能包含资本市场数据,但事实证明情况并非如此😄。
因此,异常值检测成了关键。我虽然没有探测排行榜,但仍花费大量时间对比小县的数据及其不规则的时间序列。此外,我们还需处理2021年1月数据的结构性变化以及人口数据的变动。
为此,我使用最新人口普查数据调整了目标变量,并移除了所有县在超过±7%阈值时的可疑突增:
for o in tqdm(raw.cfips.unique()):
indices = (raw['cfips']==o)
tmp = raw.loc[indices].copy().reset_index(drop=True)
var = tmp.microbusiness_density.values.copy()
var_pct = tmp.microbusiness_density.pct_change().clip(-0.07,0.07)
for j in range(40, 0, -1):
if j==18 and (var_pct[j]== -0.07 or var_pct[j]== 0.07):
var[j-1] = var[j]
else:
var[j-1] = var[j]/(1+var_pct[j])
raw.loc[indices, 'microbusiness_density'] = var
随后使用时间序列自编码器进一步去噪:
def create_autoencoder(noise=0.05):
i = tf.keras.Input(shape=(24,))
encoded = tf.keras.layers.BatchNormalization()(i)
encoded = tf.keras.layers.GaussianNoise(noise)(encoded)
encoded = tf.keras.layers.Dense(64,activation='relu')(encoded)
decoded = tf.keras.layers.Dropout(0.2)(encoded)
decoded = tf.keras.layers.Dense(24)(decoded)
x = tf.keras.layers.Dense(32,activation='relu')(decoded)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Dense(24,activation='linear')(x)
encoder = tf.keras.Model(inputs=i,outputs=x)
loss = tf.keras.losses.MeanSquaredError()
encoder.compile(optimizer=Adam(0.001),loss=loss)
return encoder
我不确定这是否会造成数据泄露,因为它在交叉验证的fold结构之前/外部应用。但它稳定了我的CV分数,对公开排行榜分数没有负面影响。因此我仅在GRU模型中使用它,XGB模型仍使用"原始"数据训练。
仅考虑拥有超过150家微型企业的县作为模型输入,低于此阈值的县直接使用最后观测值。
基于Chris的提案,我使用GRU模型,输入24个月的np.log1p(微型企业密度)序列,采用3折GroupKFold(按日期分组),预测1、3、4、5个月后的值。
第二个模型使用XGB,参考GIBA分享的方法,将1、3、4、5个月的增长率差值作为目标。虽然加入了多数县级特征,但它们解释力有限。后处理时,我将XGB预测的百分比变化按预处理后的10%和90%分位数进行截断。两个模型在最终提交中各占50%权重。
这是一个受21行代码方案启发的简单线性模型。它计算2021年1月结构性变化后21个月内各县的平均月增长率,均值限制在-0.5%至+1%之间,对活跃域名少于150的县将增长率乘以0.3(这些参数基于粗略统计:平均增长率及5%、25%、75%、95%分位数的人工判断)。对于11月和12月增长停滞的县,则永久沿用最后观测值。该方案得分4.0731,可排175名(付出10%的努力仍可获得银牌)🙀