iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
AI & Data

咖狗報到-30天玩轉Kaggle競賽系列 第 12

一起來參加Kaggle競賽-提升實戰經驗12(out-of-fold predictions)

  • 分享至 

  • xImage
  •  

昨天看到 0.9926 的分數差點開香檳,但冷靜想想,這絕對不是我的模型忽然變成神。今天的任務就是把這個 bug 修好,用正確的方法重新建立 Target Encoding,再比較三種編碼的表現。


1. 修正 Target Encoding:改用 OOF (Out-Of-Fold)

昨天的問題是我先用整份資料計算目標均值,再切訓練/驗證集,導致驗證集也偷看了答案,出現典型的 Target Leakage

今天我改用 OOF Target Encoding

  • 用 StratifiedKFold 切成 5 folds
  • 每個 fold 的編碼,只用「其他 4 folds」的資料去計算
  • 測試集用全訓練集的均值去映射
from sklearn.model_selection import StratifiedKFold, train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd

# 分出特徵和目標
y = train["rule_violation"]
X = train.drop(columns=["rule_violation"])

# 已排除目標重新取得欄位名單
cat_cols = X.select_dtypes(include=["object", "category", "bool"]).columns.tolist()
num_cols = X.select_dtypes(include=["number"]).columns.tolist()

# OOF Target Encoding
global_mean = y.mean()
train_te = pd.DataFrame(index=X.index)
test_te  = pd.DataFrame(index=test.index)

kf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

for col in cat_cols:
    oof = pd.Series(index=X.index, dtype=float)
    for tr_idx, val_idx in kf.split(X, y):
        means = pd.concat([X.iloc[tr_idx][col], y.iloc[tr_idx]], axis=1) \
                  .groupby(col)["rule_violation"].mean()
        oof.iloc[val_idx] = X.iloc[val_idx][col].map(means)
    train_te[col] = oof.fillna(global_mean)

    # 測試集:用全訓練集的均值映射
    full_means = pd.concat([X[col], y], axis=1).groupby(col)["rule_violation"].mean()
    test_te[col] = test[col].map(full_means).fillna(global_mean)

# 合併數值特徵 + TE 類別特徵
X_te = pd.concat([X[num_cols].reset_index(drop=True),
                  train_te.reset_index(drop=True)], axis=1)
T_te = pd.concat([test[num_cols].reset_index(drop=True),
                  test_te.reset_index(drop=True)], axis=1)


然後再做一次模型訓練

##  === Target Encoding + RandomForest Baseline ===
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score



# 建立 Baseline Model
X_tr, X_val, y_tr, y_val = train_test_split(X_te, y, test_size=0.2, random_state=42, stratify=y)
rf = RandomForestClassifier(n_estimators=300, random_state=42, n_jobs=-1)
rf.fit(X_tr, y_tr)
print("Val Acc:", accuracy_score(y_val, rf.predict(X_val)))

Target Encoding Baseline Accuracy

修正後的 OOF Target Encoding 分數從昨天的 0.99 掉回合理範圍(0.65),證明昨天真的是資料前處理沒有做好,導致洩漏答案。


2.提交到kaggle

接著我們比較 One-Hot 、 Frequency Encoding 和 Target Encoding 可以發現三者其實分數差不多,Target Encoding 稍微領先一點點,因此我們就已 Target Encoding 的 Baseline model 上傳至 Kaggle 。

# 用最佳表現的特徵
final_model = RandomForestClassifier(n_estimators=300, random_state=42, n_jobs=-1)
final_model.fit(X_te, y)
test_pred = final_model.predict(T_te)

submission = pd.DataFrame({
    submission.columns[0]: submission.iloc[:, 0],
    submission.columns[1]: test_pred
})
submission.to_csv("submission.csv", index=False)
print("Submission 檔案已產生,可以上傳 Kaggle leaderboard 驗證!")

而這次比賽很特別的一點是,他需要繳交的是在 kaggle 的 Notebook ,所以我們需要把在自己本機端寫好的程式,丟入 kaggle 的 Notebook 還需要注意的是比賽說明提及:Your Notebook cannot use internet access in this competition. Please disable internet in the Notebook editor and save a new version. 代表我們執行程式時,是需要跑出一個沒有網路的版本去做提交(關網路的方法如下圖)

Turn off internet

分數


3.結論

本次實驗以 Target Encoding 搭配簡單的 RandomForestClassifier 建立 Baseline Model 進行測試,最終分數約 0.533,雖然結果有限,但成功驗證了前處理流程與特徵轉換是正確的。接下來我會繼續嘗試更進階的模型與加入更多評估指標,希望可以進一步提升模型效能提升我在 kaggle leaderboard 的分數。


上一篇
一起來參加Kaggle競賽-提升實戰經驗11(Baseline model)
下一篇
一起來參加Kaggle競賽-提升實戰經驗13(Word2Vec+xgboost)
系列文
咖狗報到-30天玩轉Kaggle競賽15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言