17. LightGBM
LightGBM is another gradient boosting API.
17.1. Load data
We will use the diabetes data.
[1]:
from sklearn.datasets import load_diabetes
X, y = load_diabetes(return_X_y=True, as_frame=True)
X.shape, y.shape
[1]:
((442, 10), (442,))
[2]:
from sklearn.model_selection import train_test_split
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.10, random_state=37)
X_tr.shape, X_te.shape, y_tr.shape, y_te.shape
[2]:
((397, 10), (45, 10), (397,), (45,))
17.2. Tuning
Now, the tuning begins. Optuna requires an objective
function that takes in a trial object and returns a scalar or tuple; when a tuple of scalar values is returned, the tuning is called multiobjective tuning. In this example, we have only one objective which is to minimize the mean absolute erorr MAE
.
[3]:
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
import lightgbm as lgbm
import numpy as np
import optuna
np.random.seed(37)
optuna.logging.set_verbosity(optuna.logging.WARNING)
def get_model(imputer_params={}, regressor_params={}):
model = Pipeline([
('imputer', SimpleImputer(**imputer_params)),
('regressor', lgbm.LGBMRegressor(**regressor_params))
])
return model
def objective(trial):
i_params = {
'strategy': trial.suggest_categorical('strategy', ['mean', 'median', 'most_frequent'])
}
r_params = {
'boosting_type': 'gbdt',
'num_leaves': trial.suggest_int('num_leaves', 30, 50),
'max_depth': trial.suggest_int('max_depth', 0, 100),
'n_estimators': trial.suggest_int('n_estimators', 80, 200),
'class_weight': 'balanced',
'random_state': 37,
'n_jobs': -1
}
model = get_model(i_params, r_params)
model.fit(X_tr, y_tr)
y_pred = model.predict(X_te)
mae = mean_absolute_error(y_te, y_pred)
rmse = mean_squared_error(y_te, y_pred, squared=False)
r2s = r2_score(y_te, y_pred)
trial.set_user_attr('mae', mae)
trial.set_user_attr('rmse', rmse)
trial.set_user_attr('r2s', r2s)
return mae
After we create an objective function, we can create a study and perform optimization.
[4]:
study = optuna.create_study(**{
'study_name': 'lightgbm-study',
'storage': 'sqlite:///_temp/lightgbm-study.db',
'load_if_exists': True,
'direction': 'minimize',
'sampler': optuna.samplers.TPESampler(seed=37),
'pruner': optuna.pruners.MedianPruner(n_warmup_steps=10)
})
study.optimize(**{
'func': objective,
'n_trials': 100,
'n_jobs': 1,
'show_progress_bar': False
})
Now we may look at the best hyperparameters, value (the value we are trying to optmize for), and trial.
[5]:
study.best_params
[5]:
{'max_depth': 7, 'n_estimators': 81, 'num_leaves': 33, 'strategy': 'median'}
[6]:
study.best_value
[6]:
43.272510110290995
[7]:
study.best_trial
[7]:
FrozenTrial(number=77, values=[43.272510110290995], datetime_start=datetime.datetime(2023, 6, 1, 22, 54, 40, 530753), datetime_complete=datetime.datetime(2023, 6, 1, 22, 54, 40, 578125), params={'max_depth': 7, 'n_estimators': 81, 'num_leaves': 33, 'strategy': 'median'}, distributions={'max_depth': IntDistribution(high=100, log=False, low=0, step=1), 'n_estimators': IntDistribution(high=200, log=False, low=80, step=1), 'num_leaves': IntDistribution(high=50, log=False, low=30, step=1), 'strategy': CategoricalDistribution(choices=('mean', 'median', 'most_frequent'))}, user_attrs={'mae': 43.272510110290995, 'r2s': 0.5377439510450933, 'rmse': 56.98427363699325}, system_attrs={}, intermediate_values={}, trial_id=78, state=TrialState.COMPLETE, value=None)
17.3. Plotting
There are several plots you may use to understand the hyperparameter optmization results.
[8]:
from optuna.visualization import plot_optimization_history
plot_optimization_history(**{
'study': study
})
[9]:
from optuna.visualization import plot_parallel_coordinate
plot_parallel_coordinate(**{
'study': study
})
[10]:
from optuna.visualization import plot_param_importances
plot_param_importances(**{
'study': study
})
[11]:
from optuna.visualization import plot_slice
plot_slice(**{
'study': study,
'params': ['num_leaves', 'max_depth', 'n_estimators']
})
[12]:
from optuna.visualization import plot_contour
plot_contour(**{
'study': study,
'params': ['num_leaves', 'max_depth', 'n_estimators']
})
[13]:
from optuna.visualization import plot_edf
plot_edf(study)