引言

在机器学习中,分类问题是一个经典任务。本项目通过结合多种模型的预测结果来提升分类性能,具体使用了随机森林(Random Forest)、XGBoost 和 TabNet 这三个模型,并通过加权投票机制(民主投票)综合它们的预测。项目的目标是预测乘客是否被“运输”(Transported),这是一个二分类问题。我们还将使用 K 折交叉验证评估模型,并生成测试数据的预测结果。

数据预处理

加载数据并删除无用列

我从 train.csv 加载训练数据,并删除了 PassengerId 和 Name 两列,因为它们对预测无直接帮助:

data = pd.read_csv("train.csv")
data = data.drop(['PassengerId', 'Name'], axis=1)

处理 Cabin 列

Cabin 列包含舱位信息,格式为 deck/num/side。我将其拆分为三列,并对 deck 和 side 进行独热编码:

def split_cabin(cabin):
    if pd.isna(cabin):
        return 'Unknown', -1, 'Unknown'
    parts = cabin.split('/')
    if len(parts) == 3:
        return parts[0], int(parts[1]), parts[2]
    else:
        return 'Unknown', -1, 'Unknown'

data[['deck', 'num', 'side']] = data['Cabin'].apply(split_cabin).apply(pd.Series)
data['num'] = pd.to_numeric(data['num'], errors='coerce').fillna(-1).astype(int)
data = pd.get_dummies(data, columns=['deck', 'side'], prefix=['deck', 'side'])
data = data.drop('Cabin', axis=1)

创建 TotalSpending 特征

我将乘客的五项消费(RoomService、FoodCourt 等)相加,创建了一个新特征 TotalSpending:

data['TotalSpending'] = data[['RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck']].sum(axis=1)

处理缺失值

  • 分类特征(如 HomePlanet)用 'Unknown' 填充。
  • 数值特征(如 Age)用均值填充:
categorical_cols = ['HomePlanet', 'CryoSleep', 'Destination', 'VIP']
data[categorical_cols] = data[categorical_cols].fillna('Unknown')
numerical_cols = ['Age', 'RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck', 'num', 'TotalSpending']
data[numerical_cols] = data[numerical_cols].fillna(data[numerical_cols].mean())

独热编码和特征分离

对分类特征进行独热编码,并分离特征 X 和目标变量 y:

data = pd.get_dummies(data, columns=categorical_cols)
X = data.drop('Transported', axis=1)
y = data['Transported'].astype(int)

模型训练

使用了三种模型,并通过 K 折交叉验证(K=2)训练和评估它们:

随机森林(Random Forest)

随机森林通过构建多个决策树并聚合结果来提高性能。我使用了以下代码:

rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
rf_pred = rf_model.predict(X_val)

XGBoost

XGBoost 是一种强大的梯度提升模型。我设置了学习率和树的数量等参数:

xgb_model = XGBClassifier(learning_rate=0.05, n_estimators=200, max_depth=6, eval_metric='logloss', use_label_encoder=False)
xgb_model.fit(X_train, y_train)
xgb_pred = xgb_model.predict(X_val)

TabNet

TabNet 是一种基于神经网络的表格数据分类器。我调整了网络结构参数:

tabnet_model = TabNetClassifier(n_d=16, n_a=16, n_steps=5)
tabnet_model.fit(X_train_np, y_train_np, eval_set=[(X_val_np, y_val_np)], max_epochs=1500, patience=150)
tabnet_pred = tabnet_model.predict(X_val_np)

在交叉验证中,我对数值特征进行了标准化处理:

scaler = StandardScaler()
X_train_scaled[numerical_cols] = scaler.fit_transform(X_train[numerical_cols])
X_val_scaled[numerical_cols] = scaler.transform(X_val[numerical_cols])

民主投票机制

为了综合三个模型的预测,我设计了一个加权投票机制:

  • 随机森林权重:0.3
  • XGBoost 权重:0.4
  • TabNet 权重:0.3
    最终预测通过加权和计算,若大于等于 0.5 则为 1,否则为 0:
rf_weight = 0.3
xgb_weight = 0.4
tabnet_weight = 0.3
voting_pred = np.array([1 if (rf * rf_weight + xgb * xgb_weight + tab * tabnet_weight) >= 0.5 else 0
                        for rf, xgb, tab in zip(rf_pred, xgb_pred, tabnet_pred)])

这种方法利用了每个模型的优势,提升了整体性能。

模型评估

通过交叉验证,我收集了真实标签和预测结果,并计算了以下指标:

print("Ensemble Model - Accuracy:", accuracy_score(all_y_true, all_y_pred))
print("Ensemble Model - Precision:", precision_score(all_y_true, all_y_pred))
print("Ensemble Model - Recall:", recall_score(all_y_true, all_y_pred))
print("Ensemble Model - F1 Score:", f1_score(all_y_true, all_y_pred))

测试和提交

对测试数据,我重复了预处理步骤,并使用训练好的模型进行预测:

test_data = pd.read_csv("test.csv")
test_data_scaled[numerical_cols] = scaler.transform(test_data[numerical_cols])
rf_pred_test = rf_model.predict(test_data)
xgb_pred_test = xgb_model.predict(test_data)
tabnet_pred_test = tabnet_model.predict(test_data_np)
voting_pred_test = np.array([1 if (rf * rf_weight + xgb * xgb_weight + tab * tabnet_weight) >= 0.5 else 0
                             for rf, xgb, tab in zip(rf_pred_test, xgb_pred_test, tabnet_pred_test)])
submission = pd.DataFrame({
    'PassengerId': passenger_ids,
    'Transported': voting_pred_test.astype(bool)
})
submission.to_csv("submission.csv", index=False)