562. Predict Student Performance from Game Play | predict-student-performance-from-game-play
我尊重所有参赛者,你们在长期艰苦的战斗中表现出色,很高兴能与大家并肩作战。同时感谢我的队友(@tereka、@deepkun1995、@ryotak12、@yurimaeda)的辛勤付出。
非常高兴这是我首次获得金牌!
我们的解决方案没有特别之处:第一阶段使用1个神经网络、1个LightGBM和4个XGBoost模型(采用不同特征);第二阶段使用MLP和逻辑回归进行堆叠;第三阶段采用平均和阈值优化。
我为每个level_group单独训练XGBoost模型。基础特征与公开代码相似,包括elapsed_time_diff和hover_duration的聚合特征及其他数值特征。此外,我还加入了前一个level_group的特征和预测概率作为当前level_group的输入特征。
使用numpy和numba实现特征工程(最初使用polars,后改用队友@yurimaeda的numba方案),提交时间从2小时大幅缩短至13分钟。采用5-StratifiedGroupKFold交叉验证策略。
为每个问题创建MLP和逻辑回归模型(共18个模型/类),每个模型输出维度为(n_samples, 1)。为避免过拟合,保持模型结构简单。
MLP实现代码:
class MLP(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.head = nn.Linear(hidden_size, output_size)
self.dropout = nn.Dropout(0.2)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout(x)
x = self.head(x)
return x
对第二阶段两个模型的预测结果取平均值,并针对每个问题优化阈值:
import numpy as np
from sklearn.metrics import f1_score
from scipy.optimize import minimize
def f1_score_macro_for_thresholds(y_true, y_pred_prob, thresholds):
y_pred_binary = (y_pred_prob > thresholds).astype(int)
score = f1_score(y_true.flatten(), y_pred_binary.flatten(), average="macro")
return score
def optimize_thresholds(y_true, y_pred_prob, method="Powell"):
n_labels = y_pred_prob.shape[1]
init_thresholds = np.full(n_labels, 0.6)
objective = lambda thresholds: -f1_score_macro_for_thresholds(
y_true, y_pred_prob, thresholds
)
result = minimize(
objective, init_thresholds, bounds=[(0, 1)] * n_labels, method=method
)
return result.x
尝试多种优化方法后,Powell算法效果最佳,该方法使CV得分提升了0.008。