Your Goal: Predict the likelihood of customer churn.
import json
import os
import pickle
import time
from collections import Counter
import numpy as np
import pandas as pd
from tqdm import tqdm
import category_encoders as ce
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCA, TruncatedSVD
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectKBest, chi2, mutual_info_classif
from sklearn.linear_model import LinearRegression, LogisticRegression, Ridge, Lasso
from sklearn.metrics import (
accuracy_score, f1_score, precision_score, recall_score,
mean_absolute_error, mean_squared_error, r2_score,
root_mean_squared_error, roc_auc_score
)
from sklearn.model_selection import StratifiedKFold
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.svm import SVC, SVR
import xgboost as xg
import lightgbm as lg
import catboost as cb
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from imblearn.over_sampling import SMOTE
import optuna
import shap
import warnings
warnings.filterwarnings("ignore")
SEED = 42
np.random.seed(SEED)
c:\Users\user\miniconda3\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
train = pd.read_csv('data/data.csv')
test = pd.read_csv('data/test.csv')
train.head()
| customerID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | ... | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | Churn | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 | No |
| 1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | ... | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 | No |
| 2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | ... | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 | Yes |
| 3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | ... | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 | No |
| 4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | ... | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 | Yes |
5 rows × 21 columns
train = train.drop(columns=['customerID'])
test = test.drop(columns=['id'])
train['TotalCharges'] = pd.to_numeric(train['TotalCharges'], errors='coerce')
test['TotalCharges'] = pd.to_numeric(test['TotalCharges'], errors='coerce')
train['TotalCharges'] = train['TotalCharges'].fillna(0)
test['TotalCharges'] = test['TotalCharges'].fillna(0)
def engineer_features(df):
df = df.copy()
# Tenure groups
df['tenure_group'] = pd.cut(
df['tenure'],
bins=[-1, 12, 24, 36, 48, 60, 72],
labels=['0-12', '12-24', '24-36', '36-48', '48-60', '60-72']
).astype(str)
# Charge ratios
df['monthly_to_total_ratio'] = df['MonthlyCharges'] / (df['TotalCharges'] + 1)
df['avg_monthly_charge'] = df['TotalCharges'] / (df['tenure'] + 1)
df['charge_difference'] = df['MonthlyCharges'] - df['avg_monthly_charge']
# Service counts
service_cols = [
'PhoneService', 'MultipleLines', 'InternetService',
'OnlineSecurity', 'OnlineBackup', 'DeviceProtection',
'TechSupport', 'StreamingTV', 'StreamingMovies'
]
df['num_services'] = df[service_cols].apply(
lambda row: sum(1 for v in row if v not in ['No', 'No phone service', 'No internet service']),
axis=1
)
protection_cols = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport']
df['num_protection_services'] = df[protection_cols].apply(
lambda row: sum(1 for v in row if v == 'Yes'), axis=1
)
streaming_cols = ['StreamingTV', 'StreamingMovies']
df['num_streaming_services'] = df[streaming_cols].apply(
lambda row: sum(1 for v in row if v == 'Yes'), axis=1
)
# Interaction features
df['contract_billing'] = df['Contract'] + '_' + df['PaperlessBilling']
df['contract_payment'] = df['Contract'] + '_' + df['PaymentMethod']
df['tenure_x_monthly'] = df['tenure'] * df['MonthlyCharges']
# Flags
df['is_new_customer'] = (df['tenure'] <= 6).astype(int)
return df
# Apply on combined data so thresholds are consistent
n_train = len(train)
combined = pd.concat([train, test], axis=0, ignore_index=True)
combined = engineer_features(combined)
train = combined.iloc[:n_train].reset_index(drop=True)
test = combined.iloc[n_train:].reset_index(drop=True)
X = train.drop(columns=['Churn'])
X_test = test.copy()
y = train["Churn"].map({'No': 0, 'Yes': 1})
cat_cols = X.select_dtypes(include=['object', 'category']).columns.tolist()
# Fill NaN in categorical columns (CatBoost can't handle NaN in cat features)
for col in cat_cols:
X[col] = X[col].astype(str).replace('nan', 'Missing')
X_test[col] = X_test[col].astype(str).replace('nan', 'Missing')
# Label-encoded versions for XGBoost / LightGBM
le_dict = {}
X_encoded = X.copy()
X_test_encoded = X_test.copy()
for col in cat_cols:
le = LabelEncoder()
le.fit(pd.concat([X[col], X_test[col]], axis=0).astype(str))
X_encoded[col] = le.transform(X[col].astype(str))
X_test_encoded[col] = le.transform(X_test[col].astype(str))
le_dict[col] = le
cat_col_indices = [X_encoded.columns.get_loc(c) for c in cat_cols]
N_FOLDS = 5
skf = StratifiedKFold(n_splits=N_FOLDS, shuffle=True, random_state=SEED)
def objective_catboost(trial):
params = {
'iterations': trial.suggest_int('iterations', 300, 2000),
'depth': trial.suggest_int('depth', 4, 10),
'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3, log=True),
'l2_leaf_reg': trial.suggest_float('l2_leaf_reg', 1e-2, 10.0, log=True),
'border_count': trial.suggest_int('border_count', 32, 255),
'bagging_temperature': trial.suggest_float('bagging_temperature', 0.0, 10.0),
'random_strength': trial.suggest_float('random_strength', 0.0, 10.0),
'cat_features': cat_cols,
'verbose': 0,
'random_seed': SEED,
'eval_metric': 'Logloss',
'task_type': 'CPU'
}
scores = []
for train_idx, val_idx in skf.split(X, y):
X_tr, X_vl = X.iloc[train_idx], X.iloc[val_idx]
y_tr, y_vl = y.iloc[train_idx], y.iloc[val_idx]
model = cb.CatBoostClassifier(**params)
model.fit(X_tr, y_tr, eval_set=(X_vl, y_vl), early_stopping_rounds=50, verbose=0)
preds = model.predict_proba(X_vl)[:, 1]
scores.append(roc_auc_score(y_vl, preds))
return np.mean(scores)
study_cb = optuna.create_study(direction='maximize', study_name='catboost')
study_cb.optimize(objective_catboost, n_trials=50, show_progress_bar=True)
best_params_cb = study_cb.best_params
print(f"Best CatBoost AUC: {study_cb.best_value:.4f}")
[I 2026-03-04 21:57:57,896] A new study created in memory with name: catboost Best trial: 0. Best value: 0.848946: 2%|▏ | 1/50 [01:41<1:23:03, 101.71s/it]
[I 2026-03-04 21:59:39,605] Trial 0 finished with value: 0.8489455650962283 and parameters: {'iterations': 444, 'depth': 6, 'learning_rate': 0.08404855668901212, 'l2_leaf_reg': 9.57449874385346, 'border_count': 252, 'bagging_temperature': 1.8383396754674342, 'random_strength': 4.125046077004781}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 0. Best value: 0.848946: 4%|▍ | 2/50 [03:51<1:34:30, 118.13s/it]
[I 2026-03-04 22:01:49,232] Trial 1 finished with value: 0.8463328154014429 and parameters: {'iterations': 1703, 'depth': 10, 'learning_rate': 0.040988234045945066, 'l2_leaf_reg': 0.05449828816010084, 'border_count': 155, 'bagging_temperature': 1.7039817371742083, 'random_strength': 7.0454781899357855}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 0. Best value: 0.848946: 6%|▌ | 3/50 [04:59<1:14:37, 95.27s/it]
[I 2026-03-04 22:02:57,291] Trial 2 finished with value: 0.8461782558149228 and parameters: {'iterations': 932, 'depth': 7, 'learning_rate': 0.07389637057842925, 'l2_leaf_reg': 1.8617594600732394, 'border_count': 85, 'bagging_temperature': 0.3473719715580392, 'random_strength': 0.8984233727929414}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 0. Best value: 0.848946: 8%|▊ | 4/50 [09:24<2:04:29, 162.38s/it]
[I 2026-03-04 22:07:22,563] Trial 3 finished with value: 0.8482215108411066 and parameters: {'iterations': 1105, 'depth': 7, 'learning_rate': 0.022349535387804795, 'l2_leaf_reg': 4.355590471717159, 'border_count': 171, 'bagging_temperature': 9.236302027112433, 'random_strength': 5.437755237617701}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 0. Best value: 0.848946: 10%|█ | 5/50 [11:44<1:55:34, 154.10s/it]
[I 2026-03-04 22:09:41,985] Trial 4 finished with value: 0.8480968756622105 and parameters: {'iterations': 1368, 'depth': 7, 'learning_rate': 0.04633951061043291, 'l2_leaf_reg': 0.9613071694927249, 'border_count': 211, 'bagging_temperature': 7.7280721777151715, 'random_strength': 6.478324778773031}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 0. Best value: 0.848946: 12%|█▏ | 6/50 [16:16<2:22:30, 194.33s/it]
[I 2026-03-04 22:14:14,405] Trial 5 finished with value: 0.8488221388334887 and parameters: {'iterations': 726, 'depth': 5, 'learning_rate': 0.01489555795917187, 'l2_leaf_reg': 0.2666815325255858, 'border_count': 252, 'bagging_temperature': 5.80071407686126, 'random_strength': 2.7888060361707345}. Best is trial 0 with value: 0.8489455650962283.
Best trial: 6. Best value: 0.848962: 14%|█▍ | 7/50 [17:48<1:55:13, 160.77s/it]
[I 2026-03-04 22:15:46,076] Trial 6 finished with value: 0.848962073488757 and parameters: {'iterations': 1130, 'depth': 5, 'learning_rate': 0.08121104956935338, 'l2_leaf_reg': 0.48994386919089267, 'border_count': 90, 'bagging_temperature': 9.32088767457166, 'random_strength': 2.7333470903757573}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 16%|█▌ | 8/50 [19:29<1:39:17, 141.84s/it]
[I 2026-03-04 22:17:27,379] Trial 7 finished with value: 0.8438440740149338 and parameters: {'iterations': 536, 'depth': 8, 'learning_rate': 0.039246445292948844, 'l2_leaf_reg': 0.4254764568010471, 'border_count': 64, 'bagging_temperature': 3.1720999562449013, 'random_strength': 0.21138504783650647}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 18%|█▊ | 9/50 [20:16<1:16:37, 112.13s/it]
[I 2026-03-04 22:18:14,171] Trial 8 finished with value: 0.8463324750748346 and parameters: {'iterations': 1093, 'depth': 5, 'learning_rate': 0.218237838822657, 'l2_leaf_reg': 1.262177045158561, 'border_count': 80, 'bagging_temperature': 0.547437210031243, 'random_strength': 9.409432192169493}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 20%|██ | 10/50 [25:52<2:00:49, 181.25s/it]
[I 2026-03-04 22:23:50,196] Trial 9 finished with value: 0.8482824042292805 and parameters: {'iterations': 866, 'depth': 5, 'learning_rate': 0.01294375061397699, 'l2_leaf_reg': 0.233525437132381, 'border_count': 116, 'bagging_temperature': 7.191244422258033, 'random_strength': 6.406395677333912}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 22%|██▏ | 11/50 [26:35<1:30:15, 138.86s/it]
[I 2026-03-04 22:24:32,955] Trial 10 finished with value: 0.8469082068220309 and parameters: {'iterations': 1483, 'depth': 4, 'learning_rate': 0.16120843532650886, 'l2_leaf_reg': 0.015503196736319355, 'border_count': 33, 'bagging_temperature': 9.912989974915616, 'random_strength': 2.730778882699343}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 24%|██▍ | 12/50 [27:58<1:17:16, 122.01s/it]
[I 2026-03-04 22:25:56,435] Trial 11 finished with value: 0.8481027282783602 and parameters: {'iterations': 386, 'depth': 6, 'learning_rate': 0.10245985120173301, 'l2_leaf_reg': 8.7962578434902, 'border_count': 253, 'bagging_temperature': 3.8446457428629035, 'random_strength': 2.9145810269659584}. Best is trial 6 with value: 0.848962073488757.
Best trial: 6. Best value: 0.848962: 24%|██▍ | 12/50 [28:41<1:30:52, 143.50s/it]
[W 2026-03-04 22:26:39,847] Trial 12 failed with parameters: {'iterations': 1980, 'depth': 4, 'learning_rate': 0.12207153863740601, 'l2_leaf_reg': 0.04747241906876049, 'border_count': 119, 'bagging_temperature': 5.210355209931039, 'random_strength': 3.7746087372904213} because of the following error: KeyboardInterrupt('').
Traceback (most recent call last):
File "c:\Users\user\miniconda3\Lib\site-packages\optuna\study\_optimize.py", line 205, in _run_trial
value_or_values = func(trial)
File "C:\Users\user\AppData\Local\Temp\ipykernel_20716\3338903048.py", line 23, in objective_catboost
model.fit(X_tr, y_tr, eval_set=(X_vl, y_vl), early_stopping_rounds=50, verbose=0)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py", line 5245, in fit
self._fit(X, y, cat_features, text_features, embedding_features, None, graph, sample_weight, None, None, None, None, baseline, use_best_model,
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
eval_set, verbose, logging_level, plot, plot_file, column_description, verbose_eval, metric_period,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
silent, early_stopping_rounds, save_snapshot, snapshot_file, snapshot_interval, init_model, callbacks, log_cout, log_cerr)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py", line 2410, in _fit
self._train(
~~~~~~~~~~~^
train_pool,
^^^^^^^^^^^
...<3 lines>...
train_params["init_model"]
^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py", line 1790, in _train
self._object._train(train_pool, test_pool, params, allow_clear_pool, init_model._object if init_model else None)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "_catboost.pyx", line 5023, in _catboost._CatBoost._train
File "_catboost.pyx", line 5072, in _catboost._CatBoost._train
KeyboardInterrupt
[W 2026-03-04 22:26:39,851] Trial 12 failed with value None.
--------------------------------------------------------------------------- KeyboardInterrupt Traceback (most recent call last) Cell In[165], line 30 27 return np.mean(scores) 29 study_cb = optuna.create_study(direction='maximize', study_name='catboost') ---> 30 study_cb.optimize(objective_catboost, n_trials=50, show_progress_bar=True) 31 best_params_cb = study_cb.best_params 32 print(f"Best CatBoost AUC: {study_cb.best_value:.4f}") File c:\Users\user\miniconda3\Lib\site-packages\optuna\study\study.py:490, in Study.optimize(self, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar) 388 def optimize( 389 self, 390 func: ObjectiveFuncType, (...) 397 show_progress_bar: bool = False, 398 ) -> None: 399 """Optimize an objective function. 400 401 Optimization is done by choosing a suitable set of hyperparameter values from a given (...) 488 If nested invocation of this method occurs. 489 """ --> 490 _optimize( 491 study=self, 492 func=func, 493 n_trials=n_trials, 494 timeout=timeout, 495 n_jobs=n_jobs, 496 catch=tuple(catch) if isinstance(catch, Iterable) else (catch,), 497 callbacks=callbacks, 498 gc_after_trial=gc_after_trial, 499 show_progress_bar=show_progress_bar, 500 ) File c:\Users\user\miniconda3\Lib\site-packages\optuna\study\_optimize.py:67, in _optimize(study, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar) 65 try: 66 if n_jobs == 1: ---> 67 _optimize_sequential( 68 study, 69 func, 70 n_trials, 71 timeout, 72 catch, 73 callbacks, 74 gc_after_trial, 75 reseed_sampler_rng=False, 76 time_start=None, 77 progress_bar=progress_bar, 78 ) 79 else: 80 if n_jobs == -1: File c:\Users\user\miniconda3\Lib\site-packages\optuna\study\_optimize.py:164, in _optimize_sequential(study, func, n_trials, timeout, catch, callbacks, gc_after_trial, reseed_sampler_rng, time_start, progress_bar) 161 break 163 try: --> 164 frozen_trial_id = _run_trial(study, func, catch) 165 finally: 166 # The following line mitigates memory problems that can be occurred in some 167 # environments (e.g., services that use computing containers such as GitHub Actions). 168 # Please refer to the following PR for further details: 169 # https://github.com/optuna/optuna/pull/325. 170 if gc_after_trial: File c:\Users\user\miniconda3\Lib\site-packages\optuna\study\_optimize.py:262, in _run_trial(study, func, catch) 255 assert False, "Should not reach." 257 if ( 258 updated_state == TrialState.FAIL 259 and func_err is not None 260 and not isinstance(func_err, catch) 261 ): --> 262 raise func_err 263 return trial._trial_id File c:\Users\user\miniconda3\Lib\site-packages\optuna\study\_optimize.py:205, in _run_trial(study, func, catch) 203 with get_heartbeat_thread(trial._trial_id, study._storage): 204 try: --> 205 value_or_values = func(trial) 206 except exceptions.TrialPruned as e: 207 # TODO(mamu): Handle multi-objective cases. 208 state = TrialState.PRUNED Cell In[165], line 23, in objective_catboost(trial) 20 y_tr, y_vl = y.iloc[train_idx], y.iloc[val_idx] 22 model = cb.CatBoostClassifier(**params) ---> 23 model.fit(X_tr, y_tr, eval_set=(X_vl, y_vl), early_stopping_rounds=50, verbose=0) 24 preds = model.predict_proba(X_vl)[:, 1] 25 scores.append(roc_auc_score(y_vl, preds)) File c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py:5245, in CatBoostClassifier.fit(self, X, y, cat_features, text_features, embedding_features, graph, sample_weight, baseline, use_best_model, eval_set, verbose, logging_level, plot, plot_file, column_description, verbose_eval, metric_period, silent, early_stopping_rounds, save_snapshot, snapshot_file, snapshot_interval, init_model, callbacks, log_cout, log_cerr) 5242 if 'loss_function' in params: 5243 CatBoostClassifier._check_is_compatible_loss(params['loss_function']) -> 5245 self._fit(X, y, cat_features, text_features, embedding_features, None, graph, sample_weight, None, None, None, None, baseline, use_best_model, 5246 eval_set, verbose, logging_level, plot, plot_file, column_description, verbose_eval, metric_period, 5247 silent, early_stopping_rounds, save_snapshot, snapshot_file, snapshot_interval, init_model, callbacks, log_cout, log_cerr) 5248 return self File c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py:2410, in CatBoost._fit(self, X, y, cat_features, text_features, embedding_features, pairs, graph, sample_weight, group_id, group_weight, subgroup_id, pairs_weight, baseline, use_best_model, eval_set, verbose, logging_level, plot, plot_file, column_description, verbose_eval, metric_period, silent, early_stopping_rounds, save_snapshot, snapshot_file, snapshot_interval, init_model, callbacks, log_cout, log_cerr) 2407 allow_clear_pool = train_params["allow_clear_pool"] 2409 with plot_wrapper(plot, plot_file, 'Training plots', [_get_train_dir(self.get_params())]): -> 2410 self._train( 2411 train_pool, 2412 train_params["eval_sets"], 2413 params, 2414 allow_clear_pool, 2415 train_params["init_model"] 2416 ) 2418 # Have property feature_importance possibly set 2419 loss = self._object._get_loss_function_name() File c:\Users\user\miniconda3\Lib\site-packages\catboost\core.py:1790, in _CatBoostBase._train(self, train_pool, test_pool, params, allow_clear_pool, init_model) 1789 def _train(self, train_pool, test_pool, params, allow_clear_pool, init_model): -> 1790 self._object._train(train_pool, test_pool, params, allow_clear_pool, init_model._object if init_model else None) 1791 self._set_trained_model_attributes() File _catboost.pyx:5023, in _catboost._CatBoost._train() File _catboost.pyx:5072, in _catboost._CatBoost._train() KeyboardInterrupt:
def objective_xgboost(trial):
params = {
'n_estimators': trial.suggest_int('n_estimators', 300, 2000),
'max_depth': trial.suggest_int('max_depth', 3, 10),
'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3, log=True),
'subsample': trial.suggest_float('subsample', 0.5, 1.0),
'colsample_bytree': trial.suggest_float('colsample_bytree', 0.5, 1.0),
'reg_alpha': trial.suggest_float('reg_alpha', 1e-3, 10.0, log=True),
'reg_lambda': trial.suggest_float('reg_lambda', 1e-3, 10.0, log=True),
'min_child_weight': trial.suggest_int('min_child_weight', 1, 10),
'gamma': trial.suggest_float('gamma', 0.0, 5.0),
'objective': 'binary:logistic',
'eval_metric': 'auc',
'random_state': SEED,
'verbosity': 0,
'early_stopping_rounds': 50,
'device': 'cuda',
'tree_method': 'hist'
}
scores = []
for train_idx, val_idx in skf.split(X_encoded, y):
X_tr, X_vl = X_encoded.iloc[train_idx], X_encoded.iloc[val_idx]
y_tr, y_vl = y.iloc[train_idx], y.iloc[val_idx]
model = xg.XGBClassifier(**params)
model.fit(X_tr, y_tr, eval_set=[(X_vl, y_vl)], verbose=0)
preds = model.predict_proba(X_vl)[:, 1]
scores.append(roc_auc_score(y_vl, preds))
return np.mean(scores)
study_xgb = optuna.create_study(direction='maximize', study_name='xgboost')
study_xgb.optimize(objective_xgboost, n_trials=50, show_progress_bar=True)
best_params_xgb = study_xgb.best_params
print(f"Best XGBoost AUC: {study_xgb.best_value:.4f}")
[I 2026-03-04 07:17:45,935] A new study created in memory with name: xgboost Best trial: 0. Best value: 0.846737: 2%|▏ | 1/50 [00:04<03:48, 4.66s/it]
[I 2026-03-04 07:17:50,591] Trial 0 finished with value: 0.8467374296718375 and parameters: {'n_estimators': 496, 'max_depth': 8, 'learning_rate': 0.012864236628113318, 'subsample': 0.8166073433907668, 'colsample_bytree': 0.9164448864190609, 'reg_alpha': 1.1136455170278383, 'reg_lambda': 0.006332629757280146, 'min_child_weight': 8, 'gamma': 2.476069982657094}. Best is trial 0 with value: 0.8467374296718375.
Best trial: 0. Best value: 0.846737: 4%|▍ | 2/50 [00:05<01:58, 2.47s/it]
[I 2026-03-04 07:17:51,535] Trial 1 finished with value: 0.8460137827428271 and parameters: {'n_estimators': 804, 'max_depth': 3, 'learning_rate': 0.21786850304276598, 'subsample': 0.7430994966279258, 'colsample_bytree': 0.5955168805660132, 'reg_alpha': 6.845603351720182, 'reg_lambda': 0.6157215993031069, 'min_child_weight': 8, 'gamma': 2.1196598347299473}. Best is trial 0 with value: 0.8467374296718375.
Best trial: 0. Best value: 0.846737: 6%|▌ | 3/50 [00:06<01:22, 1.75s/it]
[I 2026-03-04 07:17:52,429] Trial 2 finished with value: 0.8461151562618505 and parameters: {'n_estimators': 954, 'max_depth': 3, 'learning_rate': 0.20327643550706168, 'subsample': 0.971779400483129, 'colsample_bytree': 0.701464984158042, 'reg_alpha': 2.2315035716374605, 'reg_lambda': 0.025587923275197315, 'min_child_weight': 2, 'gamma': 3.8662433388378616}. Best is trial 0 with value: 0.8467374296718375.
Best trial: 3. Best value: 0.846963: 8%|▊ | 4/50 [00:07<01:04, 1.41s/it]
[I 2026-03-04 07:17:53,305] Trial 3 finished with value: 0.8469627886803497 and parameters: {'n_estimators': 1962, 'max_depth': 9, 'learning_rate': 0.2581203382786872, 'subsample': 0.9168085300535684, 'colsample_bytree': 0.6515597464911167, 'reg_alpha': 3.97477465842831, 'reg_lambda': 0.00857636116611166, 'min_child_weight': 8, 'gamma': 1.8979391905726695}. Best is trial 3 with value: 0.8469627886803497.
Best trial: 4. Best value: 0.847674: 10%|█ | 5/50 [00:15<02:44, 3.67s/it]
[I 2026-03-04 07:18:00,977] Trial 4 finished with value: 0.8476739548644814 and parameters: {'n_estimators': 1991, 'max_depth': 10, 'learning_rate': 0.011136841569737084, 'subsample': 0.5991030107312154, 'colsample_bytree': 0.6914706532714088, 'reg_alpha': 5.597986647935248, 'reg_lambda': 0.08267237775303585, 'min_child_weight': 7, 'gamma': 1.19864822360089}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 12%|█▏ | 6/50 [00:19<02:57, 4.03s/it]
[I 2026-03-04 07:18:05,714] Trial 5 finished with value: 0.8460800442543256 and parameters: {'n_estimators': 346, 'max_depth': 8, 'learning_rate': 0.013681870962520208, 'subsample': 0.8793156125220523, 'colsample_bytree': 0.8591897159078525, 'reg_alpha': 1.5796522581783092, 'reg_lambda': 3.157296469566342, 'min_child_weight': 9, 'gamma': 0.16524530280023708}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 14%|█▍ | 7/50 [00:20<02:11, 3.05s/it]
[I 2026-03-04 07:18:06,761] Trial 6 finished with value: 0.8466490683945278 and parameters: {'n_estimators': 1176, 'max_depth': 7, 'learning_rate': 0.26788535434285343, 'subsample': 0.7516341544625633, 'colsample_bytree': 0.5177425879046864, 'reg_alpha': 0.6734514139829139, 'reg_lambda': 0.3688949659389196, 'min_child_weight': 9, 'gamma': 3.714610406222702}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 16%|█▌ | 8/50 [00:23<02:06, 3.01s/it]
[I 2026-03-04 07:18:09,675] Trial 7 finished with value: 0.8473866578553497 and parameters: {'n_estimators': 1541, 'max_depth': 10, 'learning_rate': 0.03295253251274497, 'subsample': 0.6513658474724591, 'colsample_bytree': 0.8782856108764467, 'reg_alpha': 0.0011438859488576833, 'reg_lambda': 2.224255157579024, 'min_child_weight': 7, 'gamma': 0.02037962567670637}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 18%|█▊ | 9/50 [00:24<01:39, 2.43s/it]
[I 2026-03-04 07:18:10,832] Trial 8 finished with value: 0.8474108002399159 and parameters: {'n_estimators': 327, 'max_depth': 10, 'learning_rate': 0.1547996323112743, 'subsample': 0.7009855872933721, 'colsample_bytree': 0.6598930575684598, 'reg_alpha': 3.9491370996015855, 'reg_lambda': 8.240748770513878, 'min_child_weight': 8, 'gamma': 2.711165601601536}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 20%|██ | 10/50 [00:27<01:42, 2.56s/it]
[I 2026-03-04 07:18:13,694] Trial 9 finished with value: 0.8476193723510779 and parameters: {'n_estimators': 1739, 'max_depth': 3, 'learning_rate': 0.029951537029287496, 'subsample': 0.754855550219123, 'colsample_bytree': 0.641249663544132, 'reg_alpha': 0.1169135585465309, 'reg_lambda': 0.04726021365128183, 'min_child_weight': 5, 'gamma': 3.378929969610525}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 4. Best value: 0.847674: 22%|██▏ | 11/50 [00:29<01:25, 2.20s/it]
[I 2026-03-04 07:18:15,058] Trial 10 finished with value: 0.8471770141553764 and parameters: {'n_estimators': 1394, 'max_depth': 6, 'learning_rate': 0.0962187926014325, 'subsample': 0.5363724986862999, 'colsample_bytree': 0.7816150605660218, 'reg_alpha': 0.007597557763363743, 'reg_lambda': 0.0017380681840752663, 'min_child_weight': 4, 'gamma': 1.4031529482625271}. Best is trial 4 with value: 0.8476739548644814.
Best trial: 11. Best value: 0.847787: 24%|██▍ | 12/50 [00:31<01:25, 2.24s/it]
[I 2026-03-04 07:18:17,411] Trial 11 finished with value: 0.8477869271879654 and parameters: {'n_estimators': 1995, 'max_depth': 5, 'learning_rate': 0.028722174466869817, 'subsample': 0.5685071545668542, 'colsample_bytree': 0.770990090162593, 'reg_alpha': 0.09699465943743135, 'reg_lambda': 0.08300575627755778, 'min_child_weight': 5, 'gamma': 4.978838371960693}. Best is trial 11 with value: 0.8477869271879654.
Best trial: 11. Best value: 0.847787: 26%|██▌ | 13/50 [00:33<01:25, 2.31s/it]
[I 2026-03-04 07:18:19,871] Trial 12 finished with value: 0.8477010145172196 and parameters: {'n_estimators': 1991, 'max_depth': 5, 'learning_rate': 0.02609165403328083, 'subsample': 0.5430595853695812, 'colsample_bytree': 0.7772220105804474, 'reg_alpha': 0.12010168826488278, 'reg_lambda': 0.1851752480148638, 'min_child_weight': 3, 'gamma': 4.95448137022775}. Best is trial 11 with value: 0.8477869271879654.
Best trial: 13. Best value: 0.848041: 28%|██▊ | 14/50 [00:36<01:29, 2.49s/it]
[I 2026-03-04 07:18:22,764] Trial 13 finished with value: 0.8480414229041313 and parameters: {'n_estimators': 1702, 'max_depth': 5, 'learning_rate': 0.028873763080278624, 'subsample': 0.5172630789654767, 'colsample_bytree': 0.7968467630448796, 'reg_alpha': 0.06126873756399033, 'reg_lambda': 0.36231209725973207, 'min_child_weight': 2, 'gamma': 4.8929946019295585}. Best is trial 13 with value: 0.8480414229041313.
Best trial: 14. Best value: 0.848202: 30%|███ | 15/50 [00:38<01:18, 2.25s/it]
[I 2026-03-04 07:18:24,460] Trial 14 finished with value: 0.8482015122886406 and parameters: {'n_estimators': 1674, 'max_depth': 5, 'learning_rate': 0.05880405325119109, 'subsample': 0.507433389608148, 'colsample_bytree': 0.9821002990274661, 'reg_alpha': 0.016092012190342436, 'reg_lambda': 1.1214921054503149, 'min_child_weight': 1, 'gamma': 4.9134082350957105}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 32%|███▏ | 16/50 [00:39<01:08, 2.01s/it]
[I 2026-03-04 07:18:25,927] Trial 15 finished with value: 0.8480590933534883 and parameters: {'n_estimators': 1612, 'max_depth': 5, 'learning_rate': 0.06772849938341542, 'subsample': 0.516039946529558, 'colsample_bytree': 0.9950859746035465, 'reg_alpha': 0.0207281995795327, 'reg_lambda': 0.937815722957446, 'min_child_weight': 1, 'gamma': 4.21033622536277}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 34%|███▍ | 17/50 [00:41<01:01, 1.87s/it]
[I 2026-03-04 07:18:27,453] Trial 16 finished with value: 0.8480733741475206 and parameters: {'n_estimators': 1283, 'max_depth': 4, 'learning_rate': 0.0696142219066409, 'subsample': 0.6274997533996826, 'colsample_bytree': 0.9848316835656703, 'reg_alpha': 0.014177762416322005, 'reg_lambda': 1.0706505122267584, 'min_child_weight': 1, 'gamma': 4.236705342652201}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 36%|███▌ | 18/50 [00:43<01:01, 1.91s/it]
[I 2026-03-04 07:18:29,462] Trial 17 finished with value: 0.8476467046383271 and parameters: {'n_estimators': 1240, 'max_depth': 4, 'learning_rate': 0.05328897104164618, 'subsample': 0.6198562615173836, 'colsample_bytree': 0.9853009625671028, 'reg_alpha': 0.003540860420179092, 'reg_lambda': 9.564179367400659, 'min_child_weight': 1, 'gamma': 4.38350485038782}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 38%|███▊ | 19/50 [00:44<00:53, 1.71s/it]
[I 2026-03-04 07:18:30,722] Trial 18 finished with value: 0.8481910928163577 and parameters: {'n_estimators': 969, 'max_depth': 4, 'learning_rate': 0.10953080560109582, 'subsample': 0.6747636219432955, 'colsample_bytree': 0.9386404966579853, 'reg_alpha': 0.02270108329763834, 'reg_lambda': 1.762100115439223, 'min_child_weight': 3, 'gamma': 3.2167117777977134}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 40%|████ | 20/50 [00:46<00:47, 1.57s/it]
[I 2026-03-04 07:18:31,956] Trial 19 finished with value: 0.8463958929207575 and parameters: {'n_estimators': 909, 'max_depth': 6, 'learning_rate': 0.11855654320115135, 'subsample': 0.6847620311578072, 'colsample_bytree': 0.9372790476090974, 'reg_alpha': 0.023136694027571448, 'reg_lambda': 2.8694904049014918, 'min_child_weight': 3, 'gamma': 3.1331996096263692}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 42%|████▏ | 21/50 [00:47<00:45, 1.59s/it]
[I 2026-03-04 07:18:33,578] Trial 20 finished with value: 0.8469514448760258 and parameters: {'n_estimators': 681, 'max_depth': 4, 'learning_rate': 0.04907115213687372, 'subsample': 0.6722316757585733, 'colsample_bytree': 0.8573257872187683, 'reg_alpha': 0.5013699628887918, 'reg_lambda': 0.20884225446042914, 'min_child_weight': 3, 'gamma': 3.0654190818163527}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 44%|████▍ | 22/50 [00:49<00:44, 1.58s/it]
[I 2026-03-04 07:18:35,160] Trial 21 finished with value: 0.8476945892176191 and parameters: {'n_estimators': 1354, 'max_depth': 4, 'learning_rate': 0.0809140710645547, 'subsample': 0.6007995779296493, 'colsample_bytree': 0.9460575631880044, 'reg_alpha': 0.013614371199969584, 'reg_lambda': 1.127060095308762, 'min_child_weight': 1, 'gamma': 4.232794753979634}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 46%|████▌ | 23/50 [00:50<00:39, 1.48s/it]
[I 2026-03-04 07:18:36,381] Trial 22 finished with value: 0.8469264451930822 and parameters: {'n_estimators': 977, 'max_depth': 4, 'learning_rate': 0.12303861259338997, 'subsample': 0.6427176641514372, 'colsample_bytree': 0.9025217604129834, 'reg_alpha': 0.005068834135376194, 'reg_lambda': 1.5979639005898938, 'min_child_weight': 2, 'gamma': 4.400995462568337}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 48%|████▊ | 24/50 [00:51<00:38, 1.46s/it]
[I 2026-03-04 07:18:37,811] Trial 23 finished with value: 0.8476158393560957 and parameters: {'n_estimators': 1118, 'max_depth': 6, 'learning_rate': 0.06349902221720807, 'subsample': 0.5877699370580762, 'colsample_bytree': 0.9587434637060352, 'reg_alpha': 0.04152007022457117, 'reg_lambda': 4.736706796105197, 'min_child_weight': 4, 'gamma': 3.7173459032550005}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 50%|█████ | 25/50 [00:53<00:40, 1.64s/it]
[I 2026-03-04 07:18:39,855] Trial 24 finished with value: 0.8474742995119435 and parameters: {'n_estimators': 1450, 'max_depth': 4, 'learning_rate': 0.04152868546267071, 'subsample': 0.7252875563096411, 'colsample_bytree': 0.8231427272471403, 'reg_alpha': 0.0019378186012083704, 'reg_lambda': 0.6280210944513941, 'min_child_weight': 1, 'gamma': 4.486805613223985}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 52%|█████▏ | 26/50 [00:55<00:36, 1.52s/it]
[I 2026-03-04 07:18:41,088] Trial 25 finished with value: 0.8459651362168378 and parameters: {'n_estimators': 1113, 'max_depth': 5, 'learning_rate': 0.10142064282244741, 'subsample': 0.7802241956916534, 'colsample_bytree': 0.9921194708461831, 'reg_alpha': 0.28155605676310974, 'reg_lambda': 4.226574011916122, 'min_child_weight': 2, 'gamma': 3.425963464388432}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 54%|█████▍ | 27/50 [00:56<00:34, 1.49s/it]
[I 2026-03-04 07:18:42,521] Trial 26 finished with value: 0.8480182116375621 and parameters: {'n_estimators': 662, 'max_depth': 3, 'learning_rate': 0.08007360671804624, 'subsample': 0.562498727561918, 'colsample_bytree': 0.9077033210885828, 'reg_alpha': 0.009044313988962433, 'reg_lambda': 1.3129957015410663, 'min_child_weight': 4, 'gamma': 3.99621494466919}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 56%|█████▌ | 28/50 [00:58<00:36, 1.67s/it]
[I 2026-03-04 07:18:44,597] Trial 27 finished with value: 0.8470941459839381 and parameters: {'n_estimators': 1793, 'max_depth': 7, 'learning_rate': 0.04266142690090833, 'subsample': 0.6238813687110757, 'colsample_bytree': 0.9707832773467323, 'reg_alpha': 0.03412756145826755, 'reg_lambda': 0.24604286745337461, 'min_child_weight': 3, 'gamma': 4.657838122375998}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 58%|█████▊ | 29/50 [00:59<00:30, 1.45s/it]
[I 2026-03-04 07:18:45,540] Trial 28 finished with value: 0.8471246566301776 and parameters: {'n_estimators': 1270, 'max_depth': 4, 'learning_rate': 0.1565467218587492, 'subsample': 0.8124443882157635, 'colsample_bytree': 0.8311897547661391, 'reg_alpha': 0.0031690611017714805, 'reg_lambda': 0.561684287661332, 'min_child_weight': 2, 'gamma': 2.876726868914763}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 60%|██████ | 30/50 [01:02<00:39, 1.96s/it]
[I 2026-03-04 07:18:48,694] Trial 29 finished with value: 0.8479603512632776 and parameters: {'n_estimators': 1512, 'max_depth': 6, 'learning_rate': 0.0212177823127342, 'subsample': 0.5039086957494522, 'colsample_bytree': 0.9320690007203571, 'reg_alpha': 0.01295629990175759, 'reg_lambda': 4.915301793538352, 'min_child_weight': 1, 'gamma': 2.2400247698928006}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 62%|██████▏ | 31/50 [01:04<00:34, 1.81s/it]
[I 2026-03-04 07:18:50,139] Trial 30 finished with value: 0.8461160022114533 and parameters: {'n_estimators': 1836, 'max_depth': 5, 'learning_rate': 0.06486037510379919, 'subsample': 0.7132426971054497, 'colsample_bytree': 0.9006939703967006, 'reg_alpha': 0.24642730561392917, 'reg_lambda': 2.01208797724776, 'min_child_weight': 6, 'gamma': 3.5195174558905147}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 14. Best value: 0.848202: 64%|██████▍ | 32/50 [01:05<00:29, 1.64s/it]
[I 2026-03-04 07:18:51,380] Trial 31 finished with value: 0.8475541505094165 and parameters: {'n_estimators': 1648, 'max_depth': 5, 'learning_rate': 0.07139479432295526, 'subsample': 0.5040568623240256, 'colsample_bytree': 0.9983392285419207, 'reg_alpha': 0.020956208267586963, 'reg_lambda': 0.8699760496679743, 'min_child_weight': 1, 'gamma': 4.10090806712388}. Best is trial 14 with value: 0.8482015122886406.
Best trial: 32. Best value: 0.848225: 66%|██████▌ | 33/50 [01:06<00:26, 1.56s/it]
[I 2026-03-04 07:18:52,769] Trial 32 finished with value: 0.8482248477292824 and parameters: {'n_estimators': 1598, 'max_depth': 3, 'learning_rate': 0.09043436044441708, 'subsample': 0.5486934326622376, 'colsample_bytree': 0.96243873069135, 'reg_alpha': 0.02417410590503186, 'reg_lambda': 0.9435688819073461, 'min_child_weight': 1, 'gamma': 4.566738076648983}. Best is trial 32 with value: 0.8482248477292824.
Best trial: 32. Best value: 0.848225: 68%|██████▊ | 34/50 [01:07<00:22, 1.39s/it]
[I 2026-03-04 07:18:53,742] Trial 33 finished with value: 0.847800767680605 and parameters: {'n_estimators': 1337, 'max_depth': 3, 'learning_rate': 0.1606683992658244, 'subsample': 0.563093104143296, 'colsample_bytree': 0.9657832514206334, 'reg_alpha': 0.04906663082478431, 'reg_lambda': 0.5291027947652482, 'min_child_weight': 2, 'gamma': 4.69240363052266}. Best is trial 32 with value: 0.8482248477292824.
Best trial: 32. Best value: 0.848225: 70%|███████ | 35/50 [01:08<00:19, 1.29s/it]
[I 2026-03-04 07:18:54,811] Trial 34 finished with value: 0.847219922022511 and parameters: {'n_estimators': 1017, 'max_depth': 3, 'learning_rate': 0.09811694987127524, 'subsample': 0.6662122916774685, 'colsample_bytree': 0.9264215382023295, 'reg_alpha': 0.0068077638995243115, 'reg_lambda': 0.018407795217349497, 'min_child_weight': 3, 'gamma': 4.635489210515709}. Best is trial 32 with value: 0.8482248477292824.
Best trial: 35. Best value: 0.848501: 72%|███████▏ | 36/50 [01:10<00:17, 1.27s/it]
[I 2026-03-04 07:18:56,025] Trial 35 finished with value: 0.8485006564798505 and parameters: {'n_estimators': 797, 'max_depth': 3, 'learning_rate': 0.11970988695379677, 'subsample': 0.6288906344096667, 'colsample_bytree': 0.8873748152045314, 'reg_alpha': 0.012536153307779714, 'reg_lambda': 0.14579395014689747, 'min_child_weight': 1, 'gamma': 3.927953487563494}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 74%|███████▍ | 37/50 [01:11<00:15, 1.18s/it]
[I 2026-03-04 07:18:56,994] Trial 36 finished with value: 0.8468721125670726 and parameters: {'n_estimators': 724, 'max_depth': 3, 'learning_rate': 0.2080475371663454, 'subsample': 0.5804781292597962, 'colsample_bytree': 0.8758429480246117, 'reg_alpha': 0.07851989858200006, 'reg_lambda': 0.14760317866344494, 'min_child_weight': 10, 'gamma': 3.8743443292716075}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 76%|███████▌ | 38/50 [01:12<00:14, 1.18s/it]
[I 2026-03-04 07:18:58,178] Trial 37 finished with value: 0.8482463251718879 and parameters: {'n_estimators': 511, 'max_depth': 3, 'learning_rate': 0.12130590076102644, 'subsample': 0.5382744194676344, 'colsample_bytree': 0.8330832870149312, 'reg_alpha': 0.02978250198548062, 'reg_lambda': 0.04351946145327605, 'min_child_weight': 2, 'gamma': 2.374776791506138}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 78%|███████▊ | 39/50 [01:13<00:12, 1.10s/it]
[I 2026-03-04 07:18:59,108] Trial 38 finished with value: 0.8468015531398903 and parameters: {'n_estimators': 475, 'max_depth': 3, 'learning_rate': 0.18001808382145104, 'subsample': 0.5391375203244775, 'colsample_bytree': 0.8275150242847181, 'reg_alpha': 0.034002355317133845, 'reg_lambda': 0.04369824297066715, 'min_child_weight': 2, 'gamma': 1.3885578775884064}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 80%|████████ | 40/50 [01:14<00:11, 1.12s/it]
[I 2026-03-04 07:19:00,272] Trial 39 finished with value: 0.8399219005981781 and parameters: {'n_estimators': 511, 'max_depth': 8, 'learning_rate': 0.13227923585988005, 'subsample': 0.9161769095490935, 'colsample_bytree': 0.8571081381786428, 'reg_alpha': 0.004659156721866526, 'reg_lambda': 0.007856676583311874, 'min_child_weight': 1, 'gamma': 1.836394814545059}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 82%|████████▏ | 41/50 [01:15<00:09, 1.08s/it]
[I 2026-03-04 07:19:01,264] Trial 40 finished with value: 0.8464010105947082 and parameters: {'n_estimators': 843, 'max_depth': 3, 'learning_rate': 0.24529273129175072, 'subsample': 0.5396217218363121, 'colsample_bytree': 0.5338506030670186, 'reg_alpha': 0.17773632798087047, 'reg_lambda': 0.012865318519708418, 'min_child_weight': 2, 'gamma': 2.5993523268108323}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 35. Best value: 0.848501: 84%|████████▍ | 42/50 [01:16<00:08, 1.12s/it]
[I 2026-03-04 07:19:02,464] Trial 41 finished with value: 0.8482609004613749 and parameters: {'n_estimators': 557, 'max_depth': 3, 'learning_rate': 0.11533987847737283, 'subsample': 0.5910775982328105, 'colsample_bytree': 0.8883530876237338, 'reg_alpha': 0.023519787005607175, 'reg_lambda': 0.11709392157293697, 'min_child_weight': 1, 'gamma': 2.2244377712607877}. Best is trial 35 with value: 0.8485006564798505.
Best trial: 42. Best value: 0.848656: 86%|████████▌ | 43/50 [01:17<00:08, 1.16s/it]
[I 2026-03-04 07:19:03,725] Trial 42 finished with value: 0.8486561904822582 and parameters: {'n_estimators': 530, 'max_depth': 3, 'learning_rate': 0.08427065884035241, 'subsample': 0.6010410385555445, 'colsample_bytree': 0.8865220226859724, 'reg_alpha': 0.010209889082617267, 'reg_lambda': 0.03936894415489394, 'min_child_weight': 1, 'gamma': 2.2021175216714903}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 88%|████████▊ | 44/50 [01:19<00:07, 1.21s/it]
[I 2026-03-04 07:19:05,038] Trial 43 finished with value: 0.8482976205855707 and parameters: {'n_estimators': 551, 'max_depth': 3, 'learning_rate': 0.0856260524992562, 'subsample': 0.6025427951891653, 'colsample_bytree': 0.7232834652769646, 'reg_alpha': 0.008109368520739766, 'reg_lambda': 0.043914465755990464, 'min_child_weight': 2, 'gamma': 2.249899762358443}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 90%|█████████ | 45/50 [01:20<00:05, 1.15s/it]
[I 2026-03-04 07:19:06,050] Trial 44 finished with value: 0.8479253280773497 and parameters: {'n_estimators': 553, 'max_depth': 3, 'learning_rate': 0.13636156775141575, 'subsample': 0.595971816483398, 'colsample_bytree': 0.7309362908589063, 'reg_alpha': 0.0018525812640187978, 'reg_lambda': 0.04880053864686244, 'min_child_weight': 2, 'gamma': 2.290735644161934}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 92%|█████████▏| 46/50 [01:21<00:04, 1.19s/it]
[I 2026-03-04 07:19:07,350] Trial 45 finished with value: 0.8459732984811922 and parameters: {'n_estimators': 424, 'max_depth': 3, 'learning_rate': 0.08734738436468373, 'subsample': 0.9899354893164114, 'colsample_bytree': 0.7405661244458953, 'reg_alpha': 0.00931252328488206, 'reg_lambda': 0.027389459457408623, 'min_child_weight': 4, 'gamma': 1.849441942055921}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 94%|█████████▍| 47/50 [01:22<00:03, 1.15s/it]
[I 2026-03-04 07:19:08,400] Trial 46 finished with value: 0.8478894983942686 and parameters: {'n_estimators': 585, 'max_depth': 3, 'learning_rate': 0.11032382233983187, 'subsample': 0.6131219056250115, 'colsample_bytree': 0.8867567580560245, 'reg_alpha': 0.006909955039409626, 'reg_lambda': 0.004107062329321802, 'min_child_weight': 2, 'gamma': 0.6455321262202389}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 96%|█████████▌| 48/50 [01:23<00:02, 1.15s/it]
[I 2026-03-04 07:19:09,532] Trial 47 finished with value: 0.8359852084924688 and parameters: {'n_estimators': 403, 'max_depth': 9, 'learning_rate': 0.18140827700998127, 'subsample': 0.652329760021533, 'colsample_bytree': 0.8088152934107196, 'reg_alpha': 0.0022711813657461557, 'reg_lambda': 0.09879692060590851, 'min_child_weight': 2, 'gamma': 2.056302418093383}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 98%|█████████▊| 49/50 [01:24<00:01, 1.12s/it]
[I 2026-03-04 07:19:10,594] Trial 48 finished with value: 0.8475779697569872 and parameters: {'n_estimators': 790, 'max_depth': 4, 'learning_rate': 0.14455780167371676, 'subsample': 0.5740591999546082, 'colsample_bytree': 0.7043594967312402, 'reg_alpha': 0.011286233642541943, 'reg_lambda': 0.061011660377573294, 'min_child_weight': 7, 'gamma': 1.6075057103648511}. Best is trial 42 with value: 0.8486561904822582.
Best trial: 42. Best value: 0.848656: 100%|██████████| 50/50 [01:26<00:00, 1.72s/it]
[I 2026-03-04 07:19:11,980] Trial 49 finished with value: 0.8471617837964805 and parameters: {'n_estimators': 307, 'max_depth': 3, 'learning_rate': 0.07580933393853528, 'subsample': 0.6477507099901392, 'colsample_bytree': 0.8428518522001033, 'reg_alpha': 0.001122005618071708, 'reg_lambda': 0.029626906389989924, 'min_child_weight': 5, 'gamma': 2.4171715216465657}. Best is trial 42 with value: 0.8486561904822582.
Best XGBoost AUC: 0.8487
def objective_lightgbm(trial):
params = {
'n_estimators': trial.suggest_int('n_estimators', 300, 2000),
'max_depth': trial.suggest_int('max_depth', 3, 12),
'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3, log=True),
'subsample': trial.suggest_float('subsample', 0.5, 1.0),
'colsample_bytree': trial.suggest_float('colsample_bytree', 0.5, 1.0),
'reg_alpha': trial.suggest_float('reg_alpha', 1e-3, 10.0, log=True),
'reg_lambda': trial.suggest_float('reg_lambda', 1e-3, 10.0, log=True),
'min_child_samples': trial.suggest_int('min_child_samples', 5, 100),
'num_leaves': trial.suggest_int('num_leaves', 20, 300),
'objective': 'binary',
'metric': 'auc',
'device': 'gpu',
'verbose': -1,
}
scores = []
for train_idx, val_idx in skf.split(X_encoded, y):
X_tr, X_vl = X_encoded.iloc[train_idx], X_encoded.iloc[val_idx]
y_tr, y_vl = y.iloc[train_idx], y.iloc[val_idx]
model = lg.LGBMClassifier(**params)
model.fit(
X_tr, y_tr, eval_set=[(X_vl, y_vl)],
callbacks=[lg.early_stopping(50, verbose=False), lg.log_evaluation(0)]
)
preds = model.predict_proba(X_vl)[:, 1]
scores.append(roc_auc_score(y_vl, preds))
return np.mean(scores)
study_lgb = optuna.create_study(direction='maximize', study_name='lightgbm')
study_lgb.optimize(objective_lightgbm, n_trials=50, show_progress_bar=True)
best_params_lgb = study_lgb.best_params
print(f"Best LightGBM AUC: {study_lgb.best_value:.4f}")
[I 2026-03-04 07:25:16,555] A new study created in memory with name: lightgbm Best trial: 0. Best value: 0.845435: 2%|▏ | 1/50 [00:13<10:38, 13.03s/it]
[I 2026-03-04 07:25:29,584] Trial 0 finished with value: 0.8454349762331457 and parameters: {'n_estimators': 1381, 'max_depth': 6, 'learning_rate': 0.011222464214799964, 'subsample': 0.8772834496241411, 'colsample_bytree': 0.708310275436183, 'reg_alpha': 0.010407514137537011, 'reg_lambda': 1.5420869539685067, 'min_child_samples': 46, 'num_leaves': 155}. Best is trial 0 with value: 0.8454349762331457.
Best trial: 1. Best value: 0.845691: 4%|▍ | 2/50 [00:22<08:52, 11.09s/it]
[I 2026-03-04 07:25:39,316] Trial 1 finished with value: 0.8456907875257349 and parameters: {'n_estimators': 1193, 'max_depth': 8, 'learning_rate': 0.012868601132743338, 'subsample': 0.8781307207190829, 'colsample_bytree': 0.7323612776124275, 'reg_alpha': 0.08006607298391034, 'reg_lambda': 0.025654364174249832, 'min_child_samples': 93, 'num_leaves': 273}. Best is trial 1 with value: 0.8456907875257349.
Best trial: 2. Best value: 0.846572: 6%|▌ | 3/50 [00:25<05:34, 7.11s/it]
[I 2026-03-04 07:25:41,692] Trial 2 finished with value: 0.8465722000156306 and parameters: {'n_estimators': 446, 'max_depth': 4, 'learning_rate': 0.1351987791843374, 'subsample': 0.6814885272390994, 'colsample_bytree': 0.9250478445840618, 'reg_alpha': 0.05286841192062867, 'reg_lambda': 0.0030147534792867203, 'min_child_samples': 19, 'num_leaves': 273}. Best is trial 2 with value: 0.8465722000156306.
Best trial: 2. Best value: 0.846572: 8%|▊ | 4/50 [00:30<04:52, 6.37s/it]
[I 2026-03-04 07:25:46,916] Trial 3 finished with value: 0.8440630336733761 and parameters: {'n_estimators': 474, 'max_depth': 7, 'learning_rate': 0.09976895249716199, 'subsample': 0.9559742099608501, 'colsample_bytree': 0.8250517061648519, 'reg_alpha': 0.0015669692700304662, 'reg_lambda': 3.2077954258900045, 'min_child_samples': 7, 'num_leaves': 270}. Best is trial 2 with value: 0.8465722000156306.
Best trial: 2. Best value: 0.846572: 10%|█ | 5/50 [00:48<08:05, 10.79s/it]
[I 2026-03-04 07:26:05,549] Trial 4 finished with value: 0.8425125571436428 and parameters: {'n_estimators': 1229, 'max_depth': 8, 'learning_rate': 0.010704197032531556, 'subsample': 0.5495612781214141, 'colsample_bytree': 0.7895915691559032, 'reg_alpha': 0.47491603685144956, 'reg_lambda': 0.07843597555419612, 'min_child_samples': 8, 'num_leaves': 104}. Best is trial 2 with value: 0.8465722000156306.
Best trial: 2. Best value: 0.846572: 12%|█▏ | 6/50 [00:54<06:29, 8.86s/it]
[I 2026-03-04 07:26:10,661] Trial 5 finished with value: 0.8435623003051894 and parameters: {'n_estimators': 1122, 'max_depth': 11, 'learning_rate': 0.05777172260157429, 'subsample': 0.5035495446508291, 'colsample_bytree': 0.9712039817832101, 'reg_alpha': 0.1124810264303263, 'reg_lambda': 0.5063426964002594, 'min_child_samples': 58, 'num_leaves': 83}. Best is trial 2 with value: 0.8465722000156306.
Best trial: 2. Best value: 0.846572: 14%|█▍ | 7/50 [01:01<05:59, 8.37s/it]
[I 2026-03-04 07:26:18,019] Trial 6 finished with value: 0.8465511147732416 and parameters: {'n_estimators': 903, 'max_depth': 12, 'learning_rate': 0.02859646524046565, 'subsample': 0.6877036424071081, 'colsample_bytree': 0.6356178299950904, 'reg_alpha': 0.013951946442018196, 'reg_lambda': 0.05963840120189229, 'min_child_samples': 92, 'num_leaves': 90}. Best is trial 2 with value: 0.8465722000156306.
Best trial: 7. Best value: 0.846963: 16%|█▌ | 8/50 [01:08<05:35, 7.99s/it]
[I 2026-03-04 07:26:25,197] Trial 7 finished with value: 0.8469628580824999 and parameters: {'n_estimators': 1408, 'max_depth': 7, 'learning_rate': 0.025104503150355915, 'subsample': 0.7136329058685237, 'colsample_bytree': 0.5244074821978648, 'reg_alpha': 3.0060179761376347, 'reg_lambda': 0.032681568252406, 'min_child_samples': 47, 'num_leaves': 294}. Best is trial 7 with value: 0.8469628580824999.
Best trial: 8. Best value: 0.847386: 18%|█▊ | 9/50 [01:11<04:25, 6.46s/it]
[I 2026-03-04 07:26:28,306] Trial 8 finished with value: 0.8473860387452747 and parameters: {'n_estimators': 676, 'max_depth': 7, 'learning_rate': 0.12310655551584529, 'subsample': 0.7481745658559806, 'colsample_bytree': 0.589285313240675, 'reg_alpha': 0.07811033182723649, 'reg_lambda': 0.008157929543107331, 'min_child_samples': 95, 'num_leaves': 47}. Best is trial 8 with value: 0.8473860387452747.
Best trial: 8. Best value: 0.847386: 20%|██ | 10/50 [01:19<04:36, 6.90s/it]
[I 2026-03-04 07:26:36,194] Trial 9 finished with value: 0.8454404132294624 and parameters: {'n_estimators': 1307, 'max_depth': 6, 'learning_rate': 0.010719662437041911, 'subsample': 0.8890465307581366, 'colsample_bytree': 0.6587226486754831, 'reg_alpha': 0.0029357471688657164, 'reg_lambda': 0.10661421450234228, 'min_child_samples': 68, 'num_leaves': 113}. Best is trial 8 with value: 0.8473860387452747.
Best trial: 8. Best value: 0.847386: 22%|██▏ | 11/50 [01:21<03:31, 5.43s/it]
[I 2026-03-04 07:26:38,294] Trial 10 finished with value: 0.8470068956675109 and parameters: {'n_estimators': 1861, 'max_depth': 3, 'learning_rate': 0.24126719850831393, 'subsample': 0.8047529908485425, 'colsample_bytree': 0.5000184951846464, 'reg_alpha': 9.008817659198558, 'reg_lambda': 0.001020109922801635, 'min_child_samples': 80, 'num_leaves': 22}. Best is trial 8 with value: 0.8473860387452747.
Best trial: 11. Best value: 0.847832: 24%|██▍ | 12/50 [01:23<02:48, 4.44s/it]
[I 2026-03-04 07:26:40,452] Trial 11 finished with value: 0.8478322961866442 and parameters: {'n_estimators': 1994, 'max_depth': 3, 'learning_rate': 0.2954855670832267, 'subsample': 0.779770066602473, 'colsample_bytree': 0.5045298181515345, 'reg_alpha': 6.389744572026091, 'reg_lambda': 0.0014002566779443854, 'min_child_samples': 77, 'num_leaves': 30}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 26%|██▌ | 13/50 [01:26<02:22, 3.85s/it]
[I 2026-03-04 07:26:42,954] Trial 12 finished with value: 0.8464040830268861 and parameters: {'n_estimators': 1764, 'max_depth': 10, 'learning_rate': 0.295691482258639, 'subsample': 0.7835231789871324, 'colsample_bytree': 0.5840776239137574, 'reg_alpha': 0.6757530738256157, 'reg_lambda': 0.005516454454897691, 'min_child_samples': 78, 'num_leaves': 20}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 28%|██▊ | 14/50 [01:28<02:02, 3.41s/it]
[I 2026-03-04 07:26:45,355] Trial 13 finished with value: 0.8465029041104121 and parameters: {'n_estimators': 773, 'max_depth': 4, 'learning_rate': 0.15488989924656488, 'subsample': 0.614096524366375, 'colsample_bytree': 0.579012381378964, 'reg_alpha': 0.5778665587467682, 'reg_lambda': 0.0059974290136803644, 'min_child_samples': 94, 'num_leaves': 58}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 30%|███ | 15/50 [01:32<02:03, 3.53s/it]
[I 2026-03-04 07:26:49,149] Trial 14 finished with value: 0.8464935741989047 and parameters: {'n_estimators': 1669, 'max_depth': 9, 'learning_rate': 0.07326287416406431, 'subsample': 0.769725282832063, 'colsample_bytree': 0.578144269047911, 'reg_alpha': 1.957489890554323, 'reg_lambda': 0.0010909492667457263, 'min_child_samples': 100, 'num_leaves': 180}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 32%|███▏ | 16/50 [01:34<01:46, 3.13s/it]
[I 2026-03-04 07:26:51,361] Trial 15 finished with value: 0.8461175456529 and parameters: {'n_estimators': 746, 'max_depth': 3, 'learning_rate': 0.1896477719340744, 'subsample': 0.6123785153781114, 'colsample_bytree': 0.6274427939085213, 'reg_alpha': 0.14983261335150422, 'reg_lambda': 0.015820149217825874, 'min_child_samples': 79, 'num_leaves': 151}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 34%|███▍ | 17/50 [01:37<01:40, 3.03s/it]
[I 2026-03-04 07:26:54,162] Trial 16 finished with value: 0.8462555649560495 and parameters: {'n_estimators': 1975, 'max_depth': 5, 'learning_rate': 0.1042199183040992, 'subsample': 0.817429925074782, 'colsample_bytree': 0.5296507208104948, 'reg_alpha': 0.02153241711840078, 'reg_lambda': 0.003037174275827135, 'min_child_samples': 66, 'num_leaves': 50}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 36%|███▌ | 18/50 [01:40<01:31, 2.84s/it]
[I 2026-03-04 07:26:56,567] Trial 17 finished with value: 0.8443467327637973 and parameters: {'n_estimators': 318, 'max_depth': 5, 'learning_rate': 0.20697415230311053, 'subsample': 0.9966138940287356, 'colsample_bytree': 0.6842135560588967, 'reg_alpha': 0.28685783229968914, 'reg_lambda': 0.29969993953842056, 'min_child_samples': 35, 'num_leaves': 207}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 38%|███▊ | 19/50 [01:47<02:08, 4.14s/it]
[I 2026-03-04 07:27:03,725] Trial 18 finished with value: 0.8459390196732297 and parameters: {'n_estimators': 1544, 'max_depth': 10, 'learning_rate': 0.03561277973883091, 'subsample': 0.7345355447338833, 'colsample_bytree': 0.8168873217576745, 'reg_alpha': 7.878162080463178, 'reg_lambda': 0.011339610348550891, 'min_child_samples': 85, 'num_leaves': 55}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 40%|████ | 20/50 [01:49<01:49, 3.66s/it]
[I 2026-03-04 07:27:06,271] Trial 19 finished with value: 0.8455231438518446 and parameters: {'n_estimators': 1013, 'max_depth': 6, 'learning_rate': 0.2971990298379211, 'subsample': 0.647874585927666, 'colsample_bytree': 0.5718301158123531, 'reg_alpha': 1.6986390394990813, 'reg_lambda': 0.0025580115019923767, 'min_child_samples': 69, 'num_leaves': 137}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 42%|████▏ | 21/50 [01:53<01:45, 3.63s/it]
[I 2026-03-04 07:27:09,823] Trial 20 finished with value: 0.8449377953785214 and parameters: {'n_estimators': 650, 'max_depth': 9, 'learning_rate': 0.11800371786593516, 'subsample': 0.8455440087648991, 'colsample_bytree': 0.6231887723346702, 'reg_alpha': 0.027938037265761276, 'reg_lambda': 0.008607948330323629, 'min_child_samples': 59, 'num_leaves': 208}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 44%|████▍ | 22/50 [01:55<01:30, 3.24s/it]
[I 2026-03-04 07:27:12,161] Trial 21 finished with value: 0.8472119171452975 and parameters: {'n_estimators': 1959, 'max_depth': 3, 'learning_rate': 0.21499234793851577, 'subsample': 0.7962892011006877, 'colsample_bytree': 0.5124294004691373, 'reg_alpha': 7.974432310299294, 'reg_lambda': 0.001130320999800955, 'min_child_samples': 80, 'num_leaves': 22}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 46%|████▌ | 23/50 [01:58<01:21, 3.01s/it]
[I 2026-03-04 07:27:14,630] Trial 22 finished with value: 0.8468348142923482 and parameters: {'n_estimators': 1955, 'max_depth': 4, 'learning_rate': 0.18148415185887715, 'subsample': 0.746218135333265, 'colsample_bytree': 0.5001661503411868, 'reg_alpha': 4.329589163673091, 'reg_lambda': 0.0015923661310921254, 'min_child_samples': 87, 'num_leaves': 40}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 48%|████▊ | 24/50 [02:01<01:18, 3.01s/it]
[I 2026-03-04 07:27:17,628] Trial 23 finished with value: 0.8467083059171798 and parameters: {'n_estimators': 1620, 'max_depth': 3, 'learning_rate': 0.08029969582862394, 'subsample': 0.8252439981189584, 'colsample_bytree': 0.5465547365438747, 'reg_alpha': 1.2468946750040257, 'reg_lambda': 0.0030427316686814725, 'min_child_samples': 100, 'num_leaves': 71}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 50%|█████ | 25/50 [02:03<01:09, 2.77s/it]
[I 2026-03-04 07:27:19,854] Trial 24 finished with value: 0.8461319150916964 and parameters: {'n_estimators': 1803, 'max_depth': 5, 'learning_rate': 0.24034220800540068, 'subsample': 0.7529086633524974, 'colsample_bytree': 0.5500389778671135, 'reg_alpha': 0.22564181536201833, 'reg_lambda': 9.051653362388857, 'min_child_samples': 73, 'num_leaves': 33}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 52%|█████▏ | 26/50 [02:06<01:07, 2.82s/it]
[I 2026-03-04 07:27:22,783] Trial 25 finished with value: 0.8465648303590241 and parameters: {'n_estimators': 1543, 'max_depth': 4, 'learning_rate': 0.1495207968940633, 'subsample': 0.9165138430062376, 'colsample_bytree': 0.5996835824682077, 'reg_alpha': 5.971564691119702, 'reg_lambda': 0.002012445318942042, 'min_child_samples': 86, 'num_leaves': 74}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 54%|█████▍ | 27/50 [02:08<00:58, 2.56s/it]
[I 2026-03-04 07:27:24,748] Trial 26 finished with value: 0.8448584255997889 and parameters: {'n_estimators': 1970, 'max_depth': 3, 'learning_rate': 0.23283899010683415, 'subsample': 0.7902816559945678, 'colsample_bytree': 0.6745486272720855, 'reg_alpha': 0.9576682137797431, 'reg_lambda': 0.007490507202136485, 'min_child_samples': 59, 'num_leaves': 120}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 56%|█████▌ | 28/50 [02:10<00:55, 2.50s/it]
[I 2026-03-04 07:27:27,116] Trial 27 finished with value: 0.8462891224687435 and parameters: {'n_estimators': 1708, 'max_depth': 5, 'learning_rate': 0.16810529723161294, 'subsample': 0.7083887252174434, 'colsample_bytree': 0.5397585060835852, 'reg_alpha': 0.006156872669436865, 'reg_lambda': 0.0010140963511084027, 'min_child_samples': 74, 'num_leaves': 44}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 58%|█████▊ | 29/50 [02:13<00:55, 2.62s/it]
[I 2026-03-04 07:27:30,010] Trial 28 finished with value: 0.8472448687822375 and parameters: {'n_estimators': 982, 'max_depth': 4, 'learning_rate': 0.08667727244243073, 'subsample': 0.8529888447341935, 'colsample_bytree': 0.5073186395238906, 'reg_alpha': 3.0298039443920817, 'reg_lambda': 0.004433169622677986, 'min_child_samples': 34, 'num_leaves': 64}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 60%|██████ | 30/50 [02:19<01:10, 3.52s/it]
[I 2026-03-04 07:27:35,627] Trial 29 finished with value: 0.8460036140514798 and parameters: {'n_estimators': 1029, 'max_depth': 6, 'learning_rate': 0.041730352748886576, 'subsample': 0.862030648950421, 'colsample_bytree': 0.7008152071596531, 'reg_alpha': 2.871329890692743, 'reg_lambda': 0.019813433516310607, 'min_child_samples': 35, 'num_leaves': 97}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 62%|██████▏ | 31/50 [02:23<01:09, 3.65s/it]
[I 2026-03-04 07:27:39,594] Trial 30 finished with value: 0.8443751246741777 and parameters: {'n_estimators': 610, 'max_depth': 7, 'learning_rate': 0.0766178001741189, 'subsample': 0.9167116818189057, 'colsample_bytree': 0.7604168410539582, 'reg_alpha': 0.0682598672039116, 'reg_lambda': 0.0046526446503240195, 'min_child_samples': 37, 'num_leaves': 65}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 64%|██████▍ | 32/50 [02:25<01:00, 3.38s/it]
[I 2026-03-04 07:27:42,320] Trial 31 finished with value: 0.8463592605310393 and parameters: {'n_estimators': 867, 'max_depth': 3, 'learning_rate': 0.12952992572199395, 'subsample': 0.8338549062089868, 'colsample_bytree': 0.5137919029631514, 'reg_alpha': 3.789106604751794, 'reg_lambda': 0.0016704159551224342, 'min_child_samples': 25, 'num_leaves': 33}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 66%|██████▌ | 33/50 [02:29<00:57, 3.38s/it]
[I 2026-03-04 07:27:45,708] Trial 32 finished with value: 0.8464834086161959 and parameters: {'n_estimators': 937, 'max_depth': 4, 'learning_rate': 0.10011399806540028, 'subsample': 0.7701513831884603, 'colsample_bytree': 0.5492548475063738, 'reg_alpha': 8.553060424352916, 'reg_lambda': 0.004000334556194712, 'min_child_samples': 46, 'num_leaves': 43}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 68%|██████▊ | 34/50 [02:32<00:56, 3.52s/it]
[I 2026-03-04 07:27:49,552] Trial 33 finished with value: 0.8472569979160355 and parameters: {'n_estimators': 1879, 'max_depth': 4, 'learning_rate': 0.06136879826347047, 'subsample': 0.8911086029744306, 'colsample_bytree': 0.6063734018851876, 'reg_alpha': 2.210449949742013, 'reg_lambda': 0.010487080546386479, 'min_child_samples': 23, 'num_leaves': 20}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 70%|███████ | 35/50 [02:37<00:57, 3.81s/it]
[I 2026-03-04 07:27:54,033] Trial 34 finished with value: 0.8460564362970612 and parameters: {'n_estimators': 1395, 'max_depth': 6, 'learning_rate': 0.05392755953225276, 'subsample': 0.8972491557074841, 'colsample_bytree': 0.6092229924447682, 'reg_alpha': 0.03947563008757373, 'reg_lambda': 0.04366542678533735, 'min_child_samples': 24, 'num_leaves': 79}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 72%|███████▏ | 36/50 [02:41<00:53, 3.83s/it]
[I 2026-03-04 07:27:57,915] Trial 35 finished with value: 0.8455499613201285 and parameters: {'n_estimators': 549, 'max_depth': 5, 'learning_rate': 0.05858194313367615, 'subsample': 0.949380678796997, 'colsample_bytree': 0.882052034325046, 'reg_alpha': 0.3041574621781891, 'reg_lambda': 0.012677077108194837, 'min_child_samples': 20, 'num_leaves': 59}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 74%|███████▍ | 37/50 [02:50<01:08, 5.29s/it]
[I 2026-03-04 07:28:06,628] Trial 36 finished with value: 0.8459802424391707 and parameters: {'n_estimators': 1125, 'max_depth': 8, 'learning_rate': 0.01594707908941444, 'subsample': 0.8620003108150928, 'colsample_bytree': 0.752846399226423, 'reg_alpha': 2.090758256811815, 'reg_lambda': 0.13318158811562553, 'min_child_samples': 13, 'num_leaves': 34}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 76%|███████▌ | 38/50 [02:53<00:58, 4.85s/it]
[I 2026-03-04 07:28:10,435] Trial 37 finished with value: 0.8462502967465552 and parameters: {'n_estimators': 1848, 'max_depth': 4, 'learning_rate': 0.048332162408319085, 'subsample': 0.9796685025216022, 'colsample_bytree': 0.7242301364077104, 'reg_alpha': 0.13572464891200794, 'reg_lambda': 0.019035535440448396, 'min_child_samples': 29, 'num_leaves': 91}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 78%|███████▊ | 39/50 [02:57<00:48, 4.38s/it]
[I 2026-03-04 07:28:13,713] Trial 38 finished with value: 0.8458234254672201 and parameters: {'n_estimators': 800, 'max_depth': 5, 'learning_rate': 0.08663016429000399, 'subsample': 0.9479676388530126, 'colsample_bytree': 0.64940654817978, 'reg_alpha': 1.0598881464778742, 'reg_lambda': 0.03386523012365037, 'min_child_samples': 42, 'num_leaves': 126}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 80%|████████ | 40/50 [03:03<00:49, 4.98s/it]
[I 2026-03-04 07:28:20,102] Trial 39 finished with value: 0.8454273404587154 and parameters: {'n_estimators': 1238, 'max_depth': 7, 'learning_rate': 0.06369075213828887, 'subsample': 0.6666596359917749, 'colsample_bytree': 0.5629819870734425, 'reg_alpha': 4.270051449286632, 'reg_lambda': 0.7778122451857931, 'min_child_samples': 11, 'num_leaves': 70}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 82%|████████▏ | 41/50 [03:06<00:38, 4.28s/it]
[I 2026-03-04 07:28:22,751] Trial 40 finished with value: 0.8474502672807601 and parameters: {'n_estimators': 1055, 'max_depth': 4, 'learning_rate': 0.12365189716587532, 'subsample': 0.9153549186882735, 'colsample_bytree': 0.5981399162033346, 'reg_alpha': 0.5082923272803268, 'reg_lambda': 0.007821837976305373, 'min_child_samples': 53, 'num_leaves': 100}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 84%|████████▍ | 42/50 [03:08<00:30, 3.83s/it]
[I 2026-03-04 07:28:25,536] Trial 41 finished with value: 0.8467770378144678 and parameters: {'n_estimators': 1022, 'max_depth': 4, 'learning_rate': 0.11898181227318057, 'subsample': 0.9066809840247678, 'colsample_bytree': 0.6156040026801247, 'reg_alpha': 1.5040249230682674, 'reg_lambda': 0.008305909721422573, 'min_child_samples': 51, 'num_leaves': 104}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 86%|████████▌ | 43/50 [03:11<00:25, 3.58s/it]
[I 2026-03-04 07:28:28,527] Trial 42 finished with value: 0.8467320598056387 and parameters: {'n_estimators': 1185, 'max_depth': 3, 'learning_rate': 0.09054328124320798, 'subsample': 0.864616986987996, 'colsample_bytree': 0.6000657355769636, 'reg_alpha': 0.7422396939621617, 'reg_lambda': 0.0036259512528662085, 'min_child_samples': 17, 'num_leaves': 54}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 88%|████████▊ | 44/50 [03:14<00:20, 3.41s/it]
[I 2026-03-04 07:28:31,550] Trial 43 finished with value: 0.8466500995516115 and parameters: {'n_estimators': 424, 'max_depth': 4, 'learning_rate': 0.07169738111721315, 'subsample': 0.9327426180924686, 'colsample_bytree': 0.6482187123825934, 'reg_alpha': 0.41337781406179214, 'reg_lambda': 0.005339399949115966, 'min_child_samples': 29, 'num_leaves': 86}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 90%|█████████ | 45/50 [03:17<00:16, 3.28s/it]
[I 2026-03-04 07:28:34,515] Trial 44 finished with value: 0.8462096855022885 and parameters: {'n_estimators': 1285, 'max_depth': 12, 'learning_rate': 0.13933791719620803, 'subsample': 0.8782117923273527, 'colsample_bytree': 0.5281564082070738, 'reg_alpha': 2.582113074013443, 'reg_lambda': 0.027299421902401786, 'min_child_samples': 53, 'num_leaves': 27}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 92%|█████████▏| 46/50 [03:20<00:12, 3.09s/it]
[I 2026-03-04 07:28:37,148] Trial 45 finished with value: 0.8462691017733389 and parameters: {'n_estimators': 681, 'max_depth': 5, 'learning_rate': 0.11009232921831234, 'subsample': 0.7207115652608378, 'colsample_bytree': 0.5942978347463717, 'reg_alpha': 0.08671599472922288, 'reg_lambda': 0.01074233548610201, 'min_child_samples': 41, 'num_leaves': 46}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 94%|█████████▍| 47/50 [03:25<00:10, 3.65s/it]
[I 2026-03-04 07:28:42,124] Trial 46 finished with value: 0.847091067778574 and parameters: {'n_estimators': 956, 'max_depth': 3, 'learning_rate': 0.030521557285321715, 'subsample': 0.846104294813945, 'colsample_bytree': 0.5627304630491523, 'reg_alpha': 0.4288930493054923, 'reg_lambda': 0.058272271802082894, 'min_child_samples': 92, 'num_leaves': 244}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 96%|█████████▌| 48/50 [03:29<00:07, 3.83s/it]
[I 2026-03-04 07:28:46,378] Trial 47 finished with value: 0.8471967610105924 and parameters: {'n_estimators': 1077, 'max_depth': 4, 'learning_rate': 0.04858647476579291, 'subsample': 0.815791498997417, 'colsample_bytree': 0.5279628820796034, 'reg_alpha': 0.001204467330837798, 'reg_lambda': 0.0019470851771421808, 'min_child_samples': 5, 'num_leaves': 63}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 98%|█████████▊| 49/50 [03:38<00:05, 5.18s/it]
[I 2026-03-04 07:28:54,696] Trial 48 finished with value: 0.845040514134976 and parameters: {'n_estimators': 846, 'max_depth': 7, 'learning_rate': 0.01929630302765626, 'subsample': 0.9691132078368797, 'colsample_bytree': 0.9322383661093803, 'reg_alpha': 5.668377146723161, 'reg_lambda': 0.006448526007508993, 'min_child_samples': 64, 'num_leaves': 109}. Best is trial 11 with value: 0.8478322961866442.
Best trial: 11. Best value: 0.847832: 100%|██████████| 50/50 [03:41<00:00, 4.43s/it]
[I 2026-03-04 07:28:57,946] Trial 49 finished with value: 0.8460504204422155 and parameters: {'n_estimators': 1348, 'max_depth': 11, 'learning_rate': 0.06752417238489604, 'subsample': 0.7695750579341819, 'colsample_bytree': 0.6770190295629418, 'reg_alpha': 0.803607248354139, 'reg_lambda': 0.015247078419313543, 'min_child_samples': 30, 'num_leaves': 20}. Best is trial 11 with value: 0.8478322961866442.
Best LightGBM AUC: 0.8478
def oof_predictions_proba(model_class, model_params, X_train, y_train, X_test,
skf, is_catboost=False):
oof_preds = np.zeros(len(X_train))
test_preds = np.zeros(len(X_test))
for fold, (train_idx, val_idx) in enumerate(skf.split(X_train, y_train)):
X_tr, X_vl = X_train.iloc[train_idx], X_train.iloc[val_idx]
y_tr, y_vl = y_train.iloc[train_idx], y_train.iloc[val_idx]
model = model_class(**model_params)
if is_catboost:
model.fit(X_tr, y_tr, eval_set=(X_vl, y_vl),
early_stopping_rounds=50, verbose=0)
else:
model.fit(X_tr, y_tr, eval_set=[(X_vl, y_vl)], verbose=0)
oof_preds[val_idx] = model.predict_proba(X_vl)[:, 1]
test_preds += model.predict_proba(X_test)[:, 1] / skf.n_splits
print(f" Fold {fold+1} AUC: {roc_auc_score(y_vl, oof_preds[val_idx]):.4f}")
print(f" Overall OOF AUC: {roc_auc_score(y_train, oof_preds):.4f}")
return oof_preds, test_preds
# CatBoost OOF
cb_params = {**best_params_cb, 'cat_features': cat_cols, 'verbose': 0,
'random_seed': SEED, 'eval_metric': 'Logloss'}
print("=== CatBoost OOF ===")
oof_cb, test_cb = oof_predictions_proba(
cb.CatBoostClassifier, cb_params, X, y, X_test, skf, is_catboost=True
)
# XGBoost OOF
xgb_params = {**best_params_xgb, 'objective': 'binary:logistic',
'eval_metric': 'auc', 'random_state': SEED, 'verbosity': 0,
'early_stopping_rounds': 50}
print("\n=== XGBoost OOF ===")
oof_xgb, test_xgb = oof_predictions_proba(
xg.XGBClassifier, xgb_params, X_encoded, y, X_test_encoded, skf
)
# LightGBM OOF
lgb_params = {**best_params_lgb, 'objective': 'binary', 'metric': 'auc',
'random_state': SEED, 'verbose': -1}
print("\n=== LightGBM OOF ===")
oof_lgb, test_lgb = oof_predictions_proba(
lg.LGBMClassifier, lgb_params, X_encoded, y, X_test_encoded, skf
)
=== CatBoost OOF === === XGBoost OOF ===
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\data.py:407, in pandas_feature_info(data, meta, feature_names, feature_types, enable_categorical) 406 try: --> 407 new_feature_types.append(_pandas_dtype_mapper[dtype.name]) 408 except KeyError: KeyError: 'object' During handling of the above exception, another exception occurred: ValueError Traceback (most recent call last) Cell In[157], line 45 41 xgb_params = {**best_params_xgb, 'objective': 'binary:logistic', 42 'eval_metric': 'auc', 'random_state': SEED, 'verbosity': 0, 43 'early_stopping_rounds': 50} 44 print("\n=== XGBoost OOF ===") ---> 45 oof_xgb, test_xgb = oof_predictions_proba( 46 xg.XGBClassifier, xgb_params, X_encoded, y, X_test_encoded, skf 47 ) 49 # LightGBM OOF 50 lgb_params = {**best_params_lgb, 'objective': 'binary', 'metric': 'auc', 51 'random_state': SEED, 'verbose': -1} Cell In[157], line 19, in oof_predictions_proba(model_class, model_params, X_train, y_train, X_test, skf, is_catboost) 16 model.fit(X_tr, y_tr, eval_set=[(X_vl, y_vl)], verbose=0) 18 oof_preds[val_idx] = model.predict_proba(X_vl)[:, 1] ---> 19 test_preds += model.predict_proba(X_test)[:, 1] / skf.n_splits 21 print(f" Fold {fold+1} AUC: {roc_auc_score(y_vl, oof_preds[val_idx]):.4f}") 23 print(f" Overall OOF AUC: {roc_auc_score(y_train, oof_preds):.4f}") File c:\Users\user\miniconda3\Lib\site-packages\xgboost\sklearn.py:1923, in XGBClassifier.predict_proba(self, X, validate_features, base_margin, iteration_range) 1921 class_prob = softmax(raw_predt, axis=1) 1922 return class_prob -> 1923 class_probs = super().predict( 1924 X=X, 1925 validate_features=validate_features, 1926 base_margin=base_margin, 1927 iteration_range=iteration_range, 1928 ) 1929 return _cls_predict_proba(self.n_classes_, class_probs, np.vstack) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\core.py:774, in require_keyword_args.<locals>.throw_if.<locals>.inner_f(*args, **kwargs) 772 for k, arg in zip(sig.parameters, args): 773 kwargs[k] = arg --> 774 return func(**kwargs) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\sklearn.py:1448, in XGBModel.predict(self, X, output_margin, validate_features, base_margin, iteration_range) 1446 if self._can_use_inplace_predict(): 1447 try: -> 1448 predts = self.get_booster().inplace_predict( 1449 data=X, 1450 iteration_range=iteration_range, 1451 predict_type="margin" if output_margin else "value", 1452 missing=self.missing, 1453 base_margin=base_margin, 1454 validate_features=validate_features, 1455 ) 1456 if _is_cupy_alike(predts): 1457 cp = import_cupy() File c:\Users\user\miniconda3\Lib\site-packages\xgboost\core.py:774, in require_keyword_args.<locals>.throw_if.<locals>.inner_f(*args, **kwargs) 772 for k, arg in zip(sig.parameters, args): 773 kwargs[k] = arg --> 774 return func(**kwargs) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\core.py:2852, in Booster.inplace_predict(self, data, iteration_range, predict_type, missing, validate_features, base_margin, strict_shape) 2850 data = pd.DataFrame(data) 2851 if _is_pandas_df(data): -> 2852 data, fns, _ = _transform_pandas_df(data, enable_categorical) 2853 if validate_features: 2854 self._validate_features(fns) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\data.py:662, in _transform_pandas_df(data, enable_categorical, feature_names, feature_types, meta) 659 raise ValueError(f"DataFrame for {meta} cannot have multiple columns") 661 feature_types, ref_categories = get_ref_categories(feature_types) --> 662 feature_names, feature_types = pandas_feature_info( 663 data, meta, feature_names, feature_types, enable_categorical 664 ) 666 arrays = pandas_transform_data(data) 667 return ( 668 PandasTransformed(arrays, ref_categories=ref_categories), 669 feature_names, 670 feature_types, 671 ) File c:\Users\user\miniconda3\Lib\site-packages\xgboost\data.py:409, in pandas_feature_info(data, meta, feature_names, feature_types, enable_categorical) 407 new_feature_types.append(_pandas_dtype_mapper[dtype.name]) 408 except KeyError: --> 409 _invalid_dataframe_dtype(data) 411 if feature_types is None and meta is None: 412 feature_types = new_feature_types File c:\Users\user\miniconda3\Lib\site-packages\xgboost\data.py:372, in _invalid_dataframe_dtype(data) 370 type_err = "DataFrame.dtypes for data must be int, float, bool or category." 371 msg = f"""{type_err} {_ENABLE_CAT_ERR} {err}""" --> 372 raise ValueError(msg) ValueError: DataFrame.dtypes for data must be int, float, bool or category. When categorical type is supplied, the experimental DMatrix parameter`enable_categorical` must be set to `True`. Invalid columns:Churn: object
from scipy.optimize import minimize
# Approach A: Optimized weighted blending
def blend_objective(weights):
w = np.array(weights)
w = w / w.sum()
blended = w[0] * oof_cb + w[1] * oof_xgb + w[2] * oof_lgb
return -roc_auc_score(y, blended)
result = minimize(
blend_objective,
x0=[1/3, 1/3, 1/3],
method='L-BFGS-B',
bounds=[(0.0, 1.0), (0.0, 1.0), (0.0, 1.0)]
)
best_weights = np.array(result.x)
best_weights = best_weights / best_weights.sum()
print(f"Optimal blend weights: CB={best_weights[0]:.3f}, XGB={best_weights[1]:.3f}, LGB={best_weights[2]:.3f}")
blended_oof = best_weights[0] * oof_cb + best_weights[1] * oof_xgb + best_weights[2] * oof_lgb
blended_test = best_weights[0] * test_cb + best_weights[1] * test_xgb + best_weights[2] * test_lgb
blend_auc = roc_auc_score(y, blended_oof)
print(f"Blended OOF AUC: {blend_auc:.4f}")
# Approach B: Logistic regression stacking
meta_train = np.column_stack([oof_cb, oof_xgb, oof_lgb])
meta_test = np.column_stack([test_cb, test_xgb, test_lgb])
meta_oof = np.zeros(len(y))
meta_test_preds = np.zeros(len(X_test))
meta_model = LogisticRegression(random_state=SEED, C=1.0)
for fold, (train_idx, val_idx) in enumerate(skf.split(meta_train, y)):
meta_model.fit(meta_train[train_idx], y.iloc[train_idx])
meta_oof[val_idx] = meta_model.predict_proba(meta_train[val_idx])[:, 1]
meta_test_preds += meta_model.predict_proba(meta_test)[:, 1] / N_FOLDS
stack_auc = roc_auc_score(y, meta_oof)
print(f"Stacked OOF AUC: {stack_auc:.4f}")
# Pick the better approach
if blend_auc >= stack_auc:
final_preds = blended_test
print(f"\nUsing BLENDING (AUC: {blend_auc:.4f})")
else:
meta_model.fit(meta_train, y)
final_preds = meta_model.predict_proba(meta_test)[:, 1]
print(f"\nUsing STACKING (AUC: {stack_auc:.4f})")
sub = pd.read_csv("data/sample_submission.csv")
sub['Churn'] = final_preds
sub.to_csv("ensemble-tuned-001.csv", index=False)
print(f"Submission saved. Shape: {sub.shape}")
sub.head()
sub1 = pd.read_csv('catboost-001.csv')
sub2 = pd.read_csv('best-public.csv')
# Try different weight combinations
best_weights = []
for w1 in [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
w2 = 1.0 - w1
ensemble = sub1.copy()
ensemble.iloc[:, 1:] = w1 * sub1.iloc[:, 1:] + w2 * sub2.iloc[:, 1:]
ensemble.to_csv(f'ensemble_w{w1:.1f}.csv', index=False)
print(f"Created ensemble with weights: {w1:.1f} / {w2:.1f}")
ensemble = sub1.copy()
for col in sub1.columns[1:]:
rank1 = sub1[col].rank(pct=True)
rank2 = sub2[col].rank(pct=True)
ensemble[col] = (rank1 + rank2) / 2
ensemble.to_csv('ensemble_rank_avg.csv', index=False)
Created ensemble with weights: 0.0 / 1.0 Created ensemble with weights: 0.1 / 0.9 Created ensemble with weights: 0.2 / 0.8 Created ensemble with weights: 0.3 / 0.7 Created ensemble with weights: 0.4 / 0.6 Created ensemble with weights: 0.5 / 0.5 Created ensemble with weights: 0.6 / 0.4 Created ensemble with weights: 0.7 / 0.3 Created ensemble with weights: 0.8 / 0.2 Created ensemble with weights: 0.9 / 0.1 Created ensemble with weights: 1.0 / 0.0