Spaces:
Runtime error
Runtime error
File size: 6,028 Bytes
003c0b8 e3188b7 4e48d40 9b132e1 e703447 9b132e1 4e48d40 9b132e1 4e48d40 003c0b8 e703447 4e48d40 003c0b8 4e48d40 e703447 4e48d40 003c0b8 4e48d40 e3188b7 4e48d40 e703447 4e48d40 e3188b7 4e48d40 003c0b8 4e48d40 e703447 003c0b8 4e48d40 e703447 4e48d40 e703447 4e48d40 e703447 4e48d40 e703447 4e48d40 e703447 4e48d40 9b132e1 e3188b7 9b132e1 e3188b7 9b132e1 05977bf 9b132e1 e3188b7 9b132e1 e703447 9b132e1 e703447 9b132e1 e3188b7 e703447 e3188b7 9b132e1 e703447 9b132e1 e3188b7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import numpy as np
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score
import sys
sys.path.insert(0, '.')
from data.data_loader import load_data, preprocess, split_and_scale
from src.smote import smote
from src.hyperparameter_tuning import grid_search
# run at import time so BEST_ALPHA/BEST_LAMBDA are available to both experiments
BEST_ALPHA, BEST_LAMBDA = grid_search()
XGB_PARAMS = dict(
n_estimators=100, max_depth=4, learning_rate=0.05,
subsample=0.7, colsample_bytree=0.7, min_child_weight=5,
reg_alpha=BEST_ALPHA, reg_lambda=BEST_LAMBDA,
eval_metric='logloss', early_stopping_rounds=15,
random_state=42,
)
# searches val set for threshold maximising F1 — test set never touched
def find_best_threshold(y_true, proba):
best_thresh, best_f1 = 0.5, 0.0
for t in np.linspace(0.1, 0.9, 81):
preds = (proba >= t).astype(int)
f1 = f1_score(y_true, preds, zero_division=0)
if f1 > best_f1:
best_f1, best_thresh = f1, t
return best_thresh, best_f1
def evaluate(model, X, y, name, threshold=0.5):
proba = model.predict_proba(X)[:, 1]
preds = (proba >= threshold).astype(int)
acc = accuracy_score(y, preds)
f1 = f1_score(y, preds, zero_division=0)
auc = roc_auc_score(y, proba)
suffix = f" (thresh={threshold:.2f})" if threshold != 0.5 else ""
print(f" {name:48s} | F1: {f1:.3f} | AUC: {auc:.3f} | Acc: {acc:.3f}{suffix}")
return acc, f1, auc
def run_condition(label, X_train, y_train, X_val, y_val, X_test, y_test,
use_smote=False, use_threshold_tuning=False):
if use_smote:
X_train, y_train = smote(X_train, np.array(y_train), k=5, random_state=42)
model = XGBClassifier(**XGB_PARAMS)
model.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=False)
threshold = 0.5
if use_threshold_tuning:
val_proba = model.predict_proba(X_val)[:, 1]
threshold, _ = find_best_threshold(y_val, val_proba)
_, f1, auc = evaluate(model, X_test, y_test, label, threshold=threshold)
return f1, auc
def run_preprocessing_experiment(df):
results = {}
X, y, _ = preprocess(df.copy(), use_domain_cleaning=False)
X_train, X_val, X_test, y_train, y_val, y_test, _ = split_and_scale(X, y)
results['Baseline'] = run_condition(
"Baseline", X_train, y_train, X_val, y_val, X_test, y_test)
X, y, _ = preprocess(df.copy(), use_domain_cleaning=True)
X_train, X_val, X_test, y_train, y_val, y_test, _ = split_and_scale(X, y)
results['Domain cleaning'] = run_condition(
"Domain cleaning", X_train, y_train, X_val, y_val, X_test, y_test)
results['+ SMOTE'] = run_condition(
"Domain cleaning + SMOTE",
X_train, y_train, X_val, y_val, X_test, y_test, use_smote=True)
results['+ Threshold'] = run_condition(
"Domain cleaning + threshold tuning",
X_train, y_train, X_val, y_val, X_test, y_test, use_threshold_tuning=True)
results['Full pipeline'] = run_condition(
"Full pipeline (cleaning + SMOTE + threshold)",
X_train, y_train, X_val, y_val, X_test, y_test,
use_smote=True, use_threshold_tuning=True)
print(f"\n {'Condition':<40} | {'F1':>6} | {'AUC':>6}")
for name, (f1, auc) in results.items():
marker = " ◀" if f1 == max(v[0] for v in results.values()) else ""
print(f" {name:<40} | {f1:>6.3f} | {auc:>6.3f}{marker}")
def regularization_experiment(df):
from sklearn.metrics import roc_auc_score
X, y, _ = preprocess(df.copy(), use_domain_cleaning=True)
X_train, X_val, X_test, y_train, y_val, y_test, _ = split_and_scale(X, y)
X_train_s, y_train_s = smote(X_train, np.array(y_train), random_state=42)
def fit_eval(name, max_depth=8, min_child_weight=1,
reg_alpha=0, reg_lambda=0,
use_early_stopping=False, n_estimators=500):
model = XGBClassifier(
n_estimators=n_estimators, max_depth=max_depth,
learning_rate=0.05, subsample=0.7, colsample_bytree=0.7,
min_child_weight=min_child_weight,
reg_alpha=reg_alpha, reg_lambda=reg_lambda,
eval_metric='logloss', random_state=42,
**(dict(early_stopping_rounds=20) if use_early_stopping else {}),
)
fit_kw = dict(eval_set=[(X_val, y_val)], verbose=False) \
if use_early_stopping else dict(verbose=False)
model.fit(X_train_s, y_train_s, **fit_kw)
stopped_at = (model.best_iteration + 1) if use_early_stopping else n_estimators
train_auc = roc_auc_score(y_train_s, model.predict_proba(X_train_s)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
gap = train_auc - test_auc
print(f" {name:<42s} | train: {train_auc:.3f} | test: {test_auc:.3f} | gap: {gap:.3f} | trees: {stopped_at}")
return gap, test_auc
print(f"\n {'Condition':<42s} | train AUC | test AUC | gap | trees")
r = {}
r['No reg'] = fit_eval("No regularization (depth=8, min_child=1)")
r['L2'] = fit_eval("L2 only (reg_lambda=5.0)", reg_lambda=5.0)
r['L1'] = fit_eval("L1 only (reg_alpha=2.0)", reg_alpha=2.0)
r['L1+L2'] = fit_eval("L1 + L2 (alpha=2.0, lambda=5.0)", reg_alpha=2.0, reg_lambda=5.0)
r['ES'] = fit_eval("Early stopping only (depth=8)", use_early_stopping=True)
r['Production'] = fit_eval("L1 + L2 + early stopping ◀ production",
max_depth=4, min_child_weight=5,
reg_alpha=BEST_ALPHA, reg_lambda=BEST_LAMBDA,
use_early_stopping=True)
bg, ba = r['No reg']
fg, fa = r['Production']
print(f"\n gap {bg:.3f} → {fg:.3f} | test AUC {ba:.3f} → {fa:.3f}")
if __name__ == '__main__':
df = load_data()
run_preprocessing_experiment(df)
regularization_experiment(df) |