562. Predict Student Performance from Game Play | predict-student-performance-from-game-play
我要感谢主办方提供了这个非常有趣且具有挑战性的项目。同时我也非常感谢Kaggle上所有的公开分享,这是一次疯狂的学习经历。如果没有所有公开的笔记本、讨论帖和以往的竞赛解决方案,我不可能在这次竞赛中取得成功。
我使用大部分原始数据进行训练,包括仅完成0-4级和5-12级会话的数据。总共约38,000个完整会话和约58,000个会话。使用原始数据使CV分数提高了0.001以上。我只使用Kaggle数据进行验证。
我的初始数据预处理只是按级别组和索引排序,与推理过程中的处理方式相同。此外,我的实验表明使用悬停持续时间没有帮助,因此在排序后我删除了悬停行,并将会话从0到len(session)重新索引。
我花费了大量时间实验Transformer,最终得到了一个轻量级模型,在公开和私有LB上达到0.698,CV分数为0.702。
class NN(nn.Module):
def __init__(self, num_cont_cols, embed_dim, num_layers, num_heads, max_seq_len):
super(NN, self).__init__()
self.emb_cont = nn.Sequential(
nn.Linear(num_cont_cols, embed_dim//2),
nn.LayerNorm(embed_dim//2)
)
self.emb_cats = nn.Sequential(
nn.Embedding(max_seq_len + 1, embed_dim//2),
nn.LayerNorm(embed_dim//2)
)
encoder_layer = nn.TransformerEncoderLayer(
d_model=embed_dim,
nhead=num_heads,
dim_feedforward=embed_dim,
dropout=0.1,
batch_first=True,
activation="relu",
)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
self.clf_heads = nn.ModuleList([
nn.Linear(embed_dim, out_dim) for out_dim in [3, 10, 5]
])
def forward(self, x, grp):
emb_conts = self.emb_cont(x[:, :, :-1])
emb_cats = self.emb_cats(x[:, :, -1].type(torch.int32))
x = torch.cat([emb_conts, emb_cats], dim=2)
x = self.encoder(x)
x = x.mean(dim=1)
x = self.clf_heads[["0-4", "5-12", "13-22"].index(grp)](x)
return x.unsqueeze(2)
我发现Transformer很容易过拟合数据,因此为了提高信噪比,我执行了以下操作:
这是我最强的单模型,公开LB 0.701,私有LB 0.702,CV 0.7029。值得注意的是,我展平了5个Transformer输入列(不包括分类列),并将所有值用作单独的特征。
其他特征主要来自公开内核中的统计信息,如分类变量的时间和索引差值的均值和最大值。这些统计在应用Transformer输入过滤之前计算。
从早期开始,我为每个级别组训练一个模型,将问题编号作为特征。我发现与为每个问题使用模型相比,CV提高了约0.0002。这可能是随机性导致的,但我选择使用它,因为我认为3个模型而不是18个会让我的实验过程更简单。对Transformer也采用了类似的推理。
本质上与XGBoost相同。CV 0.7022。
我为每个问题训练了一个线性回归元模型,使用上述模型的输出概率作为输入来生成最终预测。我还包含了过去问题以及一些未来问题的概率!例如,训练预测问题2的回归模型使用了问题1-3的概率作为输入;预测问题7时使用了问题1-13的概率;预测问题16时使用了问题1-18的概率。在输入线性回归之前,我先对3个种子取平均以提高鲁棒性。
最终结果为公开LB 0.702,私有LB 0.703,CV 0.7044。
我尽可能尝试相信CV,但我的CV和LB之间持续的差距直到最后几天都让我感到可疑。然后我意识到一个原因可能是我的选定阈值在测试数据上不是最优的。我用最高CV解决方案提交了几次,只改变阈值,发现它确实不是最优的,并且导致的LB分数变化比最近大多数实验都要大。因此最后我选择了3个相同的解决方案,使用不同的阈值:0.60(在LB上表现最佳)、0.62(在CV期间最佳)和0.64。结果是0.61本可以得到0.704的私有分数,但我不后悔 ;)
感谢您的阅读!