def fit_eval_and_log(model, name, filename, params, fit_kwargs=None): print(f"\n--- Training Model: {name} ---") start_time = time.time() model.fit(X_train, y_train, **(fit_kwargs or {})) print(f"[Training Info] Model training completed in {time.time() - start_time:.3f} seconds.") preds = model.predict(X_test) probs = model.predict_proba(X_test)[:, 1] if hasattr(model, "predict_proba") else preds.astype(float) metrics = { "Accuracy": round(accuracy_score(y_test, preds), 6), "Precision": round(precision_score(y_test, preds, zero_division=0), 6), "Recall": round(recall_score(y_test, preds, zero_division=0), 6), "AUC-ROC": round(roc_auc_score(y_test, probs), 6), "AUC-PR": round(average_precision_score(y_test, probs), 6), } print(f"{name} Test AUC-PR:", metrics["AUC-PR"]) joblib.dump(model, filename) log_experiment_run(name, params, metrics) return metrics # Baseline vs. tuned, run back to back so the comparison is apples to apples xgb_base = xgb.XGBClassifier(use_label_encoder=False, eval_metric="logloss", random_state=42) fit_eval_and_log( xgb_base, "XGBoost (Baseline)", "xgboost_model.joblib", xgb_base.get_params(), fit_kwargs={"eval_set": [(X_train, y_train), (X_test, y_test)], "verbose": 10} ) xgb_tuned_params = tuned_params.get("xgboost", { "n_estimators": 150, "max_depth": 6, "learning_rate": 0.1, "subsample": 0.8, "colsample_bytree": 0.8, "random_state": 42 }) xgb_tuned = xgb.XGBClassifier(**xgb_tuned_params, use_label_encoder=False, eval_metric="logloss") fit_eval_and_log(xgb_tuned, "XGBoost (Tuned)", "xgboost_model_tuned.joblib", xgb_tuned_params) lgb_base = lgb.LGBMClassifier(random_state=42, verbose=-1) fit_eval_and_log(lgb_base, "LightGBM (Baseline)", "lightgbm_model.joblib", lgb_base.get_params())