<jupyter_start><jupyter_text>Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. Tune LightGBM with FLAML Library 1. IntroductionFLAML is a Python library (https://github.com/microsoft/FLAML) designed to automatically produce accurate machine learning models with low computational cost. It is fast and economical. The simple and lightweight design makes it easy to use and extend, such as adding new learners. FLAML can - serve as an economical AutoML engine,- be used as a fast hyperparameter tuning tool, or - be embedded in self-tuning software that requires low latency & resource in repetitive   tuning tasks.In this notebook, we demonstrate how to use FLAML library to tune hyperparameters of LightGBM with a regression example.FLAML requires `Python>=3.6`. To run this notebook example, please install flaml with the `notebook` option:```bashpip install flaml[notebook]```<jupyter_code>!pip install flaml[notebook];<jupyter_output><empty_output><jupyter_text>2. Regression Example Load data and preprocessDownload [houses dataset](https://www.openml.org/d/537) from OpenML. The task is to predict median price of the house in the region based on demographic composition and a state of housing market in the region.<jupyter_code>from flaml.data import load_openml_dataset
X_train, X_test, y_train, y_test = load_openml_dataset(dataset_id=537, data_dir='./')<jupyter_output>load dataset from ./openml_ds537.pkl
Dataset name: houses
X_train.shape: (15480, 8), y_train.shape: (15480,);
X_test.shape: (5160, 8), y_test.shape: (5160,)<jupyter_text>Run FLAMLIn the FLAML automl run configuration, users can specify the task type, time budget, error metric, learner list, whether to subsample, resampling strategy type, and so on. All these arguments have default values which will be used if users do not provide them.<jupyter_code>''' import AutoML class from flaml package '''
from flaml import AutoML
automl = AutoML()
settings = {
    "time_budget": 240,  # total running time in seconds
    "metric": 'r2',  # primary metrics for regression can be chosen from: ['mae','mse','r2','rmse','mape']
    "estimator_list": ['lgbm'],  # list of ML learners; we tune lightgbm in this example
    "task": 'regression',  # task type    
    "log_file_name": 'houses_experiment.log',  # flaml log file
    "seed": 7654321,    # random seed
}
'''The main flaml automl API'''
automl.fit(X_train=X_train, y_train=y_train, **settings)<jupyter_output>[flaml.automl: 09-29 23:10:08] {1446} INFO - Data split method: uniform
[flaml.automl: 09-29 23:10:08] {1450} INFO - Evaluation method: cv
[flaml.automl: 09-29 23:10:08] {1496} INFO - Minimizing error metric: 1-r2
[flaml.automl: 09-29 23:10:08] {1533} INFO - List of ML learners in AutoML Run: ['lgbm']
[flaml.automl: 09-29 23:10:08] {1763} INFO - iteration 0, current learner lgbm
[flaml.automl: 09-29 23:10:08] {1880} INFO - Estimated sufficient time budget=3832s. Estimated necessary time budget=4s.
[flaml.automl: 09-29 23:10:08] {1952} INFO -  at 0.4s,	estimator lgbm's best error=0.7383,	best estimator lgbm's best error=0.7383
[flaml.automl: 09-29 23:10:08] {1763} INFO - iteration 1, current learner lgbm
[flaml.automl: 09-29 23:10:08] {1952} INFO -  at 0.6s,	estimator lgbm's best error=0.4774,	best estimator lgbm's best error=0.4774
[flaml.automl: 09-29 23:10:08] {1763} INFO - iteration 2, current learner lgbm
[flaml.automl: 09-29 23:10:09] {1952} INFO -  at 0.8s,	estimator lgbm's best [...]<jupyter_text>Best model and metric<jupyter_code>''' retrieve best config'''
print('Best hyperparmeter config:', automl.best_config)
print('Best r2 on validation data: {0:.4g}'.format(1-automl.best_loss))
print('Training duration of best run: {0:.4g} s'.format(automl.best_config_train_time))
automl.model.estimator
import matplotlib.pyplot as plt
plt.barh(automl.model.estimator.feature_name_, automl.model.estimator.feature_importances_)
''' pickle and save the automl object '''
import pickle
with open('automl.pkl', 'wb') as f:
    pickle.dump(automl, f, pickle.HIGHEST_PROTOCOL)
''' compute predictions of testing dataset ''' 
y_pred = automl.predict(X_test)
print('Predicted labels', y_pred)
print('True labels', y_test)
''' compute different metric values on testing dataset'''
from flaml.ml import sklearn_metric_loss_score
print('r2', '=', 1 - sklearn_metric_loss_score('r2', y_pred, y_test))
print('mse', '=', sklearn_metric_loss_score('mse', y_pred, y_test))
print('mae', '=', sklearn_metric_loss_score('mae', y_pred, y_test))
from flaml.data import get_output_from_log
time_history, best_valid_loss_history, valid_loss_history, config_history, metric_history = \
    get_output_from_log(filename=settings['log_file_name'], time_budget=60)

for config in config_history:
    print(config)
import numpy as np

plt.title('Learning Curve')
plt.xlabel('Wall Clock Time (s)')
plt.ylabel('Validation r2')
plt.scatter(time_history, 1 - np.array(valid_loss_history))
plt.step(time_history, 1 - np.array(best_valid_loss_history), where='post')
plt.show()<jupyter_output><empty_output><jupyter_text>3. Comparison with alternatives FLAML's accuracy<jupyter_code>print('flaml (4min) r2', '=', 1 - sklearn_metric_loss_score('r2', y_pred, y_test))<jupyter_output>flaml (4min) r2 = 0.8505434326525669<jupyter_text>Default LightGBM<jupyter_code>from lightgbm import LGBMRegressor
lgbm = LGBMRegressor()
lgbm.fit(X_train, y_train)
y_pred = lgbm.predict(X_test)
from flaml.ml import sklearn_metric_loss_score
print('default lgbm r2', '=', 1 - sklearn_metric_loss_score('r2', y_pred, y_test))<jupyter_output>default lgbm r2 = 0.8296179648694404<jupyter_text>Optuna LightGBM Tuner<jupyter_code># !pip install optuna==2.8.0;
from sklearn.model_selection import train_test_split
train_x, val_x, train_y, val_y = train_test_split(X_train, y_train, test_size=0.1)
import optuna.integration.lightgbm as lgb
dtrain = lgb.Dataset(train_x, label=train_y)
dval = lgb.Dataset(val_x, label=val_y)
params = {
    "objective": "regression",
    "metric": "regression",
    "verbosity": -1,
}
%%time
model = lgb.train(params, dtrain, valid_sets=[dtrain, dval], verbose_eval=10000)        

y_pred = model.predict(X_test)
from flaml.ml import sklearn_metric_loss_score
print('Optuna LightGBM Tuner r2', '=', 1 - sklearn_metric_loss_score('r2', y_pred, y_test))<jupyter_output>Optuna LightGBM Tuner r2 = 0.8444445782478855<jupyter_text>4. Add a customized LightGBM learner in FLAMLThe native API of LightGBM allows one to specify a custom objective function in the model constructor. You can easily enable it by adding a customized LightGBM learner in FLAML. In the following example, we show how to add such a customized LightGBM learner with a custom objective function.  Create a customized LightGBM learner with a custom objective function<jupyter_code>import numpy as np 

''' define your customized objective function '''
def my_loss_obj(y_true, y_pred):
    c = 0.5
    residual = y_pred - y_true
    grad = c * residual /(np.abs(residual) + c)
    hess = c ** 2 / (np.abs(residual) + c) ** 2
    # rmse grad and hess
    grad_rmse = residual
    hess_rmse = 1.0
    
    # mae grad and hess
    grad_mae = np.array(residual)
    grad_mae[grad_mae > 0] = 1.
    grad_mae[grad_mae <= 0] = -1.
    hess_mae = 1.0

    coef = [0.4, 0.3, 0.3]
    return coef[0] * grad + coef[1] * grad_rmse + coef[2] * grad_mae, \
        coef[0] * hess + coef[1] * hess_rmse + coef[2] * hess_mae


from flaml.model import LGBMEstimator

''' create a customized LightGBM learner class with your objective function '''
class MyLGBM(LGBMEstimator):
    '''LGBMEstimator with my_loss_obj as the objective function
    '''

    def __init__(self, **config):
        super().__init__(objective=my_loss_obj, **config)<jupyter_output><empty_output><jupyter_text>Add the customized learner in FLAML<jupyter_code>automl = AutoML()
automl.add_learner(learner_name='my_lgbm', learner_class=MyLGBM)
settings = {
    "time_budget": 150,  # total running time in seconds
    "metric": 'r2',  # primary metrics for regression can be chosen from: ['mae','mse','r2']
    "estimator_list": ['my_lgbm',],  # list of ML learners; we tune lightgbm in this example
    "task": 'regression',  # task type    
    "log_file_name": 'houses_experiment_my_lgbm.log',  # flaml log file
}
automl.fit(X_train=X_train, y_train=y_train, **settings)
print('Best hyperparmeter config:', automl.best_config)
print('Best r2 on validation data: {0:.4g}'.format(1-automl.best_loss))
print('Training duration of best run: {0:.4g} s'.format(automl.best_config_train_time))

y_pred = automl.predict(X_test)
print('Predicted labels', y_pred)
print('True labels', y_test)

from flaml.ml import sklearn_metric_loss_score
print('r2', '=', 1 - sklearn_metric_loss_score('r2', y_pred, y_test))
print('mse', '=', sklearn_metric_loss_score('mse', y_pred, y_test))
print('mae', '=', sklearn_metric_loss_score('mae', y_pred, y_test))<jupyter_output>Best hyperparmeter config: {'n_estimators': 95, 'num_leaves': 221, 'min_child_samples': 10, 'learning_rate': 0.4130805075333343, 'log_max_bin': 10, 'colsample_bytree': 0.8422311526890249, 'reg_alpha': 0.007704104902643932, 'reg_lambda': 0.003151767359549649}
Best r2 on validation data: 0.8368
Training duration of best run: 6.404 s
Predicted labels [161485.59767093 248585.87889042 157837.93378105 ... 184356.07034452
 223247.80995858 259281.61167122]
True labels 14740    136900.0
10101    241300.0
20566    200700.0
2670      72500.0
15709    460000.0
           ...   
13132    121200.0
8228     137500.0
3948     160900.0
8522     227300.0
16798    265600.0
Name: median_house_value, Length: 5160, dtype: float64
r2 = 0.8429833151406843
mse = 2075526075.9236276
mae = 30102.910560642205
{'fraction_non_alphanumeric': 0.11639613725087322, 'fraction_numerical': 0.0732484076433121, 'mean_word_length': 5.313229571984436, 'pattern_counts': {'":': 14, '<': 32, '<?xml version=': 0, '>': 33, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '85544', 'license': 'MIT', 'n_tokens_mistral': 3954, 'n_tokens_neox': 3453, 'n_words': 957, 'path': 'notebook/automl_lightgbm.ipynb', 'repo_name': 'Shao-kun-Zhang/FLAML', 'size': '9734'}