619. Playground Series - Season 4, Episode 7 | playground-series-s4e7
首先,我要感谢 Kaggle 团队组织这次比赛。这是我第一次处理如此大的数据集,这让项目从一开始就令人兴奋。在这篇文章中,我将简要概述我的方法。
在比赛初期,由于数据量巨大,我选择使用 Logistic Regression(逻辑回归)对数据进行建模。这种方法提供了一些关于数据的初步见解。例如,当我使用 TargetEncoding(目标编码)时,Logistic Regression 模型的性能显著提高。这表明某些特征虽然是数字存储的,但应被视为类别特征。您可以在这篇 帖子 中找到更多细节。
我同时使用了比赛数据集和原始数据集。
为了减少内存使用,我考虑了以下预处理步骤:
def converting_datatypes(df, df_train=False):
df = df.copy()
if df_train==False:
df['Policy_Sales_Channel'] = np.where(df['Policy_Sales_Channel']==144., 145., df['Policy_Sales_Channel'])
df['Policy_Sales_Channel'] = np.where(df['Policy_Sales_Channel']==149., 150., df['Policy_Sales_Channel'])
df['Age'] = df['Age'].astype('int8')
df['Driving_License'] = df['Driving_License'].astype('int8')
df['Region_Code'] = df['Region_Code'].astype('int8')
df['Previously_Insured'] = df['Previously_Insured'].astype('int8')
df['Annual_Premium'] = df['Annual_Premium'].astype('int32')
df['Policy_Sales_Channel'] = df['Policy_Sales_Channel'].astype('int16')
df['Vintage'] = df['Vintage'].astype('int16')
df['Gender'] = df['Gender'].map({'Female': 0, 'Male': 1}).astype('int8')
df['Vehicle_Age'] = df['Vehicle_Age'].map({'< 1 Year': 0,
'1-2 Year': 1,
'> 2 Years': 2}).astype('int8')
df['Vehicle_Damage'] = df['Vehicle_Damage'].map({'No': 0, 'Yes': 1}).astype('int8')
if df_train==True:
df['Response'] = df['Response'].astype('int8')
return df
我考虑了以下特征:
def fe(df_train, df_test, df_original):
n = df_train.shape[0]
m = df_test.shape[0]
p = n+m
df_tot = pd.concat([df_train, df_test, df_original], axis=0).reset_index(drop=True)
df_tot['interaction_1'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Vehicle_Age']).to_numpy())[0]
df_tot['interaction_2'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Vehicle_Damage']).to_numpy())[0]
df_tot['interaction_3'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Vintage']).to_numpy())[0]
df_tot['interaction_4'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Annual_Premium']).to_numpy())[0]
df_tot['interaction_5'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Gender']).to_numpy())[0]
df_tot['interaction_6'] = pd.factorize((df_tot['Previously_Insured'] + df_tot['Driving_License']).to_numpy())[0]
df_tot['interaction_7'] = pd.factorize((df_tot['Vehicle_Age'] + df_tot['Vehicle_Damage']).to_numpy())[0]
df_tot['interaction_8'] = pd.factorize((df_tot['Vehicle_Age'] + df_tot['Driving_License']).to_numpy())[0]
return [df_tot[:n], df_tot.iloc[n:p].drop(columns=['Response'], axis=1), df_tot[p:]]
我考虑了以下模型:
下表显示了所考虑的每个模型在 10 折交叉验证中的最佳性能。
| 模型 | 比赛数据 | 比赛 + 原始数据 |
|---|---|---|
| CatBoost | 0.895311 | 0.895819 |
| LGBM | 0.892605 | 0.892753 |
| TensorFlow | 0.892083 | 0.892213 |
| XGBoost | 0.890959 | 0.89105 |
| Random Forest | 0.873091 | 0.875128 |
在 Kaggle 社区中,众所周知可以通过集成不同模型的预测来优化 ROC-AUC 分数。为了实现这一点,我采用了爬山策略(Hill Climbing)。这种策略类似于爬山,涉及以线性方式组合模型预测,只要目标指标改善,就始终向上移动。最终的集成包括 24 个模型:
| 模型 | 比赛数据 | 比赛 + 原始数据 |
|---|---|---|
| CatBoost | 4 个模型 | 4 个模型 |
| LGBM | 3 个模型 | 3 个模型 |
| TensorFlow | 3 个模型 | 3 个模型 |
| XGBoost | 1 个模型 | 1 个模型 |
| Random Forest | 1 个模型 | 1 个模型 |
从上表可以看出,重要的是要注意并非所有模型都是在相同的数据上训练的。例如,4 个 CatBoost 模型是在比赛数据上训练的;然而,不同的特征被用来训练这些模型。
最后,我使用 @paddykb 在此 帖子 中提出的建议对爬山集成的预测进行了后处理。
期待下一期比赛。