メインコンテンツへスキップ
見出し画像

Python機械学習(GBDT):XGBoost

    記載内容が多くなる+とりあえず使いたいため作成=>追って追記予定

    1.概要

     今回はGradient Boosting Decision Tree勾配ブースティング決定木の一つであるXGBoostを紹介します。

    2.XGBoostについて

    2-1.モデルの概要・特徴

     Gradient Boosting Decision Tree(GBDT)は下記手法を組み合わたモデルであり、テーブルデータ表形式に強いため多次元データの回帰・分類分析に向いています。

    ●勾配降下法(Gradient)
    ●Boosting(アンサンブル)
    ●決定木(Decision Tree)

     GBDTの特徴としては下記があります。

    ★数値の大きさスケーリングはモデルで補正されるため正規化数値の前処理しなくてもよい
    ●欠損値があってもそのまま処理が可能である。
    ●分岐の繰り返しで変数間の相互作用を反映:One-hot Encodingだけでなく、Label Encodingでも十分な精度が出る。

     なおGBDTは高精度が期待されるモデルですが高精度を目指すにはデータの特徴量を作ることが重要になります不要な項目を抜いたり、新しく追加したりなど。

    2-2.データ構造:DMatrix

    追って

    2-3.API:Learning API/Scikit-Learn API

      XGBoostのAPIはLearning APIとScikit Learn APIの2種あります書き方が2通り。基本的には好きな方でよいと思います。

    2-4.設定用パラメータ

     XGBoostをインスタンス化時に使用するパラメータは下記の通りです。

    【XGBoostのパラメータ】
    ●silent:1にすることで学習時に出てくる表示をなくすことができる。
    ●eval_metric:損失関数(目的関数)の設定
    ●tree_method(※GPU可):exact/ gpu exact
    ●objective{default=reg:squarederror}:学習方法の設定(下記は主要一覧)
     ->reg:squarederror: regression with squared loss.
     ->reg:squaredlogerror: regression with squared log loss
     ->reg:logistic: logistic regression.
     ->binary:logistic: 2値の分類のlogistic regression, output probability
     ->multi:softmax: set XGBoost to do multiclass classification
    ●predictor(※GPU可): cpu_predictor/gpu_predictor

    2-5.ハイパーパラメーター

     XGBoostで調整するハイパーパラメータの一部を紹介します。

    【XGBoostのハイパーパラメータ】
    ●booster(ブースター)
    :gbtree(デフォルト), gbliner, dartの3種から設定
     ->gblinearは線形モデル、dartはdropoutを適用します。
    ●eta(学習率lr){defalut:0.3}:学習時の重みの更新率を調整
     ->lrを小さくし決定木の数を増やすと精度向上が見込めるが時間がかかる
    ●n_estimators:決定技の数
    ●min_child_weight{defalut:1}:決定木の葉の重みの下限
     ->小さいほど過学習寄り(0.1~10.0くらいで調整)
    ●max_depth{defalut:6}:木構造の深さ
     ->深いほど表現力は高いが過学習となる(3~9くらいで調整)
    ●subsample{defalut:1}:決定木ごとの訓練データからのサンプリング割合
     ->ランダム性が入る:過学習時に値を減らしてみる(0.6~0.95) 
    ●gamma{defalut:0}:決定木の葉ノードを分岐させるために必要なも目的変数の最小値:値が大きくなると分岐しにくくなる
    ●alpha{defalut:0}:決定木の葉ノードの重みに対するL1正則化の強度
    ●lambda{defalut:1}:決定木の葉ノードの重みに対するL2正則化の強度

    XGBoost公式:XGBoost Parameters、Notes on Parameter Tuning

    【XGBoost.cv()メソッドのハイパーパラメータ】
    ●num_boost_round {defalut:10}:決定木の数(Boostingの反復回数)
     ->値を1000のように大きめにしてEarly stoppingと併用すると便利
    ●early_stopping_rounds{defalut:None}:Early stoppingの監視回数
     ->設定するならとりあえず50くらいにしておいて、後で調整

    3.Learning API

     追って

    4.Scikit-Learn API

     サンプルデータを使用してXGBoostを使用してみます。サンプルデータは下記のとおりです。通常は特徴量エンジニアリングをしますが今回はデータをそのまま使用します。

    [In]
    import sklearn.datasets as datasets
    import pandas as pd
    from sklearn.model_selection import train_test_split
    
    cancer = datasets.load_breast_cancer() #分類データ(Classification)
    
    def make_data(data, dftype = True):
        X, y = data.data, data.target
        columns = data.feature_names
        if dftype:
            X = pd.DataFrame(X, columns=columns)
            y = pd.DataFrame(y, columns=['target'])
        return X, y
    
    def split_data(X: pd.DataFrame, y: pd.DataFrame, test_size: float = 0.3, random_state: int = 0):
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=random_state)
        return X_train, X_test, y_train, y_test
    
    
    X, y = make_data(cancer)
    X_train, X_test, y_train, y_test = split_data(X, y)
    print('Cancer data:','X_train.shape', X_train.shape, 'X_test.shape', X_test.shape, 'y_train.shape', y_train.shape, 'y_test.shape', y_test.shape)
    [Out]
    Cancer data: X_train.shape (398, 30) X_test.shape (171, 30) y_train.shape (398, 1) y_test.shape (171, 1)

    4-1.分類分析:XGBClassifier

     分類問題を解く場合Cancerデータは2値分類は下記のとおりです。精度は96%でそれなりに良いです。

    [In]
    import xgboost as xgb
    from sklearn.metrics import confusion_matrix
    import seaborn as sns
    import matplotlib.pyplot as plt
    import japanize_matplotlib
    
    
    #モデルの作成・学習・評価
    model = xgb.XGBClassifier(random_state=0) #XGBoostの分類モデルを作成
    model.fit(X_train, y_train) #学習
    y_pred = model.predict(X_test) #予測
    score = model.score(X_test, y_test) #正解率
    print(f'score{score:.2f}')
    
    #混合行列(Confusion Matrix)
    matrix = confusion_matrix(y_test, y_pred) 
    matrix = pd.DataFrame(matrix, columns=['0:悪性', '1:良性'], index=['0:悪性', '1:良性'])
    plt.figure(figsize=(6,6))
    sns.heatmap(matrix, annot=True, fmt='d', cmap='Blues', cbar=False)
    
    #重要度分析
    importance = model.feature_importances_
    df_imp = pd.Series(importance, index=X_train.columns).sort_values(ascending=True)
    plt.figure(figsize=(12,6))
    plt.barh(df_imp.index, df_imp)
    [Out]
    score0.96
    画像
    画像

    4-2.回帰分析:XGBRegressor

     回帰分析出力値が数値の場合は下記のとおりです。分類問題のScoreは精度(正解数÷データ数)ですが下記の回帰分析ではMSEのため平均二乗誤差参考値です。
     下記より今回は十分な精度が出ていないことが確認されました。(特徴量が不十分かも?)

    [In]
    from sklearn.metrics import r2_score
    
    diabetes = datasets.load_diabetes() #回帰データ(Regression)
    X, y = make_data(diabetes)
    X_train, X_test, y_train, y_test = split_data(X, y)
    print('Cancer data:','X_train.shape', X_train.shape, 'X_test.shape', X_test.shape, 'y_train.shape', y_train.shape, 'y_test.shape', y_test.shape)
    
    #モデルの作成・学習・評価
    model = xgb.XGBRegressor(objective = 'reg:squarederror', random_state=0) #XGBoostの分類モデルを作成
    model.fit(X_train, y_train) #学習
    y_pred = model.predict(X_test) #予測
    score = model.score(X_test, y_test) #正解率
    print(f'score(MSE){score:.3f}', f'r2_score{r2_score(y_test, y_pred):.3f}') #SCOREはR2値(決定係数)と同じであることを確認
    
    #予測精度の可視化
    plt.figure(figsize=(6,6))
    plt.scatter(y_test, y_pred)
    plt.plot([0, y_test.max()], [0, y_test.max()], c='k')
    plt.xlabel('y_test(正解値)'); plt.ylabel('y_pred(予測値)')
    plt.grid()
    
    #重要度分析
    importance = model.feature_importances_
    df_imp = pd.Series(importance, index=X_train.columns).sort_values(ascending=True)
    plt.figure(figsize=(12,6))
    plt.barh(df_imp.index, df_imp)
    [Out]
    Cancer data: X_train.shape (309, 10) X_test.shape (133, 10) y_train.shape (309, 1) y_test.shape (133, 1)
    score(MSE)0.246 r2_score0.246
    画像
    画像

    4ー3.ハイパーパラメータの調整:グリッドサーチ

     XGBoostのハイパーパラメータを調整して最適解を探っていきます。

    [In1]
    from sklearn.model_selection import GridSearchCV
    
    params ={'max_depth':[3,5,7],
                'min_child_weight':[1.0, 2.0, 4.0],
                }
    
    #モデルの作成・学習・評価
    model = xgb.XGBRegressor(objective = 'reg:squarederror', tree_method='gpu_hist' , random_state=0) #XGBoostの分類モデルを作成
    
    model_grid = GridSearchCV(model, params, cv=5)
    
    model_grid.fit(X_train,
                    y_train,
                    early_stopping_rounds=50,
                    eval_set=[(X_train, y_train)],
                    verbose=0)
    [In2]
    model_best = model_grid.best_estimator_
    y_pred = model_best.predict(X_test) #予測
    score = model_best.score(X_test, y_test) #正解率
    print(f'score(MSE){score:.2f}')
    
    #予測精度の可視化
    plt.figure(figsize=(6,6))
    plt.scatter(y_test, y_pred)
    plt.plot([0, y_test.max()], [0, y_test.max()], c='k')
    plt.xlabel('y_test(正解値)'); plt.ylabel('y_pred(予測値)')
    plt.grid()
    
    #重要度分析
    importance = model_best.feature_importances_
    df_imp = pd.Series(importance, index=X_train.columns).sort_values(ascending=True)
    plt.figure(figsize=(12,6))
    plt.barh(df_imp.index, df_imp)
    [Out]
    score(MSE)0.14

     精度が落ちたけどなんでだろう・・・・・(細かい部分は追って確認)

    5.精度向上のコツ

    5-1.ハイパーパラメータ調整

     XGBoostと同じGBDTモデルであるLightGBMの公式Docs:For Better Accuradyより、ハイパーパラメータ調整のコツは下記の通りです。

    1. Use large max_bin (may be slower):大きめのmax_bin使用

    2. Use small learning_rate with large num_iterations:小さめの学習率使用

    3. Use large num_leaves (may cause over-fitting):大きめのnum_leaves使用

    4. Use bigger training data:大量の学習データを使用

      • 1, 3で表現力が向上する反面、過学習の恐れがあるためデータ数が必要

    5. Try dart:dartを使用



    参考資料

    ●Complete Guide to Parameter Tuning in XGBoost with codes in Python


    あとがき

     XGBoostはDMatrixという型で処理しているが、PandasのDataFrameで直接処理が可能である。ただここら辺のまとまりが十分に理解できていないため、作りながら体裁をまとめていきたいです。

    【追加内容】

    • 調整できるハイパーパラメータの追加

    • CPUとGPUの切り替え

    • DMatrixとPandas使用での差異

    • 可視化=>複数の木構造をまとめて出力(参考用)

     ずっと独学でやって実装した後に下記本を読んだのだけどもっと早く出会えたらよかった。


     
     

    KIYO

     
     
    普段は製造業で企画/開発/設計しております。記事はプログラミング・機械学習、IoT関係の記事をメインで作成し、なるべく1つの記事で知りたいことを網羅していきます。内容は学術的より実装・アウトプット(ほしくなるもの)を重視して作成しています。 面白そうな仕事があればやりたいです!

    あなたへのおすすめ