<jupyter_start><jupyter_text>AutoGluon and probability calibration  確率補正に必要なsklearn APIの取り付け本連載では分類モデルの予測値を信頼性曲線にプロットしたり、クラス確率に近づける確率補正について取り上げています。前回、sklearn APIが元々備わっていたLightGBMモデルを対象にしましたが、今回は、[AutoGluon Tabular](https://pypi.org/project/autogluon.tabular/) という AutoML を対象に、確率補正に必要なAPIメソッドを取り付ける具体例をご紹介します。  ライブラリの用意sklearn を使って信頼性曲線を書いたり確率補正します。図形は Matplotlib と Plotly で作ります。補正対象のモデルとしては [AutoGluon Tabular](https://pypi.org/project/autogluon.tabular/)を使います。AutoGluon内部では [lightgbm](https://lightgbm.readthedocs.io/en/latest/),[catboost](https://catboost.ai/),[xgboost](https://xgboost.readthedocs.io/en/latest/)などが使われます。Condaやpipでそれぞれインストールできます。  サンプルデータ[Adult Census Income (国勢調査の成人収入)](https://archive.ics.uci.edu/ml/datasets/census+income)を使います。5万ドル以上の年収があるかどうかを分類するデータセットです。このデータは元々正例の割合が少なく、偏っていますが、更にノイズを投入しました。<jupyter_code>import numpy as np
import shap
import sklearn
from sklearn.model_selection import train_test_split

## Census income
X, y = shap.datasets.adult()
X = X.values

print("Original dataframe shape", X.shape)
n_samples, n_features = X.shape

# Add noise
random_state = np.random.RandomState(0)
X = X + 4 * random_state.randn(n_samples, n_features)
X = np.c_[X, random_state.randn(n_samples, 100 * n_features)]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=random_state
)
print("Noisy dataframe shape", X.shape)
print("Classes", np.unique(y))

X_test, X_calib, y_test, y_calib = train_test_split(
    X_test,
    y_test,
    test_size=4000 / len(X_test),
    random_state=random_state,
)
print("学習・補正・テスト用データ比率", np.array([len(X_train), len(X_calib), len(X_test)]) / len(X))
from autogluon.tabular import TabularDataset

tr_data = TabularDataset(X_train)
tr_data["y"] = y_train
tr_data.head()
te_data = TabularDataset(X_test)
te_data["y"] = y_test
te_data.head()
tr_data.y.describe()
te_data.y.describe()<jupyter_output><empty_output><jupyter_text>モデル学習 AutoGluonモデルを学習データにフィットさせます。<jupyter_code>from autogluon.tabular import TabularPredictor

save_path = "trained-model"
predictor = TabularPredictor(label="y", path=save_path).fit(
    tr_data, hyperparameters="toy", time_limit=30
)<jupyter_output>Warning: path already exists! This predictor may overwrite an existing predictor! path="trained-model"
Beginning AutoGluon training ... Time limit = 30s
AutoGluon will save models to "trained-model/"
AutoGluon Version:  0.1.0
Train Data Rows:    24420
Train Data Columns: 1212
Preprocessing data ...
AutoGluon infers your prediction problem is: 'binary' (because only two unique label-values observed).
	2 unique label values:  [False, True]
	If 'binary' is not the correct problem_type, please manually specify the problem_type argument in fit() (You may specify problem_type as one of: ['binary', 'multiclass', 'regression'])
Selected class <--> label mapping:  class 1 = True, class 0 = False
Using Feature Generators to preprocess the data ...
Fitting AutoMLPipelineFeatureGenerator...
	Available Memory:                    6459.76 MB
	Train Data (Original)  Memory Usage: 236.78 MB (3.7% of available memory)
	Inferring data type of each feature based on column values. Set feature_metadata_in t[...]<jupyter_text>Sklearnラッパーsklearnを使って確率補正を行うために、必要なインタフェースを用意する。 試験データでメトリック AUC, Brier を図り、信頼性曲線を書いてみます。<jupyter_code>from fastcore.basics import store_attr


class AutoGluonWrapper:
    """
    sklearnを使って信頼性曲線を描いたり、確率補正を行うために、
    必要なインタフェースを用意する。
    """

    def __init__(
        self,
        trained_model_path,  # AutoGluon学習済みモデルの保存パス
        classes_,  # sklearn APIに求められる属性
    ):
        store_attr()

    def load_model(self):
        """ AutoGluon学習済みモデルをロード """
        self.ag_model = TabularPredictor.load(self.trained_model_path)

    def fit(self):
        """ sklearn API に求められるメソッド """
        return True

    def predict_proba(self, X):
        """ sklearn API に求められるメソッド """
        X = TabularDataset(X)
        proba = self.ag_model.predict_proba(X)
        return proba.values
ag_ = AutoGluonWrapper(save_path, classes_=np.unique(y))
ag_.load_model()<jupyter_output><empty_output><jupyter_text>信頼性曲線 試験データに対してメトリック AUC, Brier を図り、信頼性曲線を書いてみます。前回定義したメソッド `plot_calibration_curve` を使います。<jupyter_code>from kowaza.proba_calib import plot_calibration_curve
plot_calibration_curve(dict(AutoGluon=ag_), X_test, y_test)<jupyter_output>ntree_limit is deprecated, use `iteration_range` or model slicing instead.<jupyter_text>確率補正の実施補正するために[sklearn.calibration. CalibratedClassifierCV](https://scikit-learn.org/stable/modules/generated/sklearn.calibration.CalibratedClassifierCV.htmlsklearn.calibration.CalibratedClassifierCV)を使います。 `cv = "prefit"` と指定することによって、ベースモデルが学習済みであり、補正モデルに渡すデータは全量補正用であることを伝えます。今回は確率補正方法として `sigmoid` と `isotonic` をそれぞれ使ってみましょう。<jupyter_code>from sklearn.calibration import CalibratedClassifierCV, calibration_curve

sigmoid = CalibratedClassifierCV(ag_, cv="prefit", method="sigmoid")
sigmoid.fit(X_calib, y_calib)
isotonic = CalibratedClassifierCV(ag_, cv="prefit", method="isotonic")
isotonic.fit(X_calib, y_calib)<jupyter_output>ntree_limit is deprecated, use `iteration_range` or model slicing instead.<jupyter_text>補正前と補正後のモデルの信頼性曲線を同じ図に書いて比較してみましょう。<jupyter_code>plot_calibration_curve(
    dict(
        AutoGluon=ag_,
        Sigmoid=sigmoid,
        Isotonic=isotonic,
    ),
    X_test,
    y_test,
)<jupyter_output>ntree_limit is deprecated, use `iteration_range` or model slicing instead.
{'fraction_non_alphanumeric': 0.10379793510324484, 'fraction_numerical': 0.008296460176991151, 'mean_word_length': 5.919642857142857, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 22, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '655732', 'license': 'Apache-2.0', 'n_tokens_mistral': 2505, 'n_tokens_neox': 2358, 'n_words': 364, 'path': 'nbs/15-autogluon.ipynb', 'repo_name': 'vochicong/nbdev_trial', 'size': '5424'}