xgboostの使い方：irisデータで多クラス分類

**xgboost**は、決定木モデルの1種である**GBDT**を扱うライブラリです。
インストールし使用するまでの手順をまとめました。
様々な言語で使えますが、Pythonでの使い方について記載しています。

# GBDTとは

- 決定木モデルの一種
- 勾配ブースティング木
- Gradient Boosting Decision Tree

同じ決定木モデルではランダムフォレストが有名ですが、下記記事が違いを簡潔にまとめられていました。
[【機械学習】決定木モデルの違いをまとめてみた - Qiita](https://qiita.com/takuya_tsurumi/items/23fdc43ee0e54ec7c87e)

# GBDTの特徴

- 簡単に良い精度が出やすい
- 欠損値を扱える
- 扱えるのは数値データ

使いやすく精度も良いことから、機械学習コンペティションのKaggleで人気があります。

# [1] 使い方
scikit-learnのデータセットの1つである、irisデータ(アヤメの品種データ)を利用しました。OSはAmazon Linux2です。

## [1-1] インストール
私が利用しているAmazon Linux2では次の通りです。環境ごとのインストール手順は公式に載っています。
[Installation Guide &#8212; xgboost 1.1.0-SNAPSHOT documentation](https://xgboost.readthedocs.io/en/latest/build.html)

```bash
pip3 install xgboost
```

## [1-2] インポート

```python
import xgboost as xgb
```

## [1-3] irisデータの取得
特別な手順はありません。irisデータを取得して、pandasのDataFrameとSeriesを作成します。

```python
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()

iris_data = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_target = pd.Series(iris.target)
```

## [1-4] 訓練データとテストデータの取得
ここも特別な手順はなく、scikit-learnの`train_test_split`でデータを訓練用とテスト用に分割します。

```python
from sklearn.model_selection import train_test_split

train_x, test_x, train_y, test_y = train_test_split(iris_data, iris_target, test_size=0.2, shuffle=True)
```

## [1-5] xgboost用の型に変換する
xgboostでは`DMatrix`を使用します。

```python
dtrain = xgb.DMatrix(train_x, label=train_y)
```

`DMatrix`はnumpyの`ndarray`やpandasの`DataFrame`から作成できるので、データの扱いに苦労することは無いでしょう。

扱えるデータの種類は公式に詳しく載っています。
[Python Package Introduction &#8212; xgboost 1.1.0-SNAPSHOT documentation](https://xgboost.readthedocs.io/en/latest/python/python_intro.html#data-interface)

## [1-6] パラメータの設定
各種パラメータの設定を行います。

```python
param = {'max_depth': 2, 'eta': 1, 'objective': 'multi:softmax', 'num_class': 3}
```

各パラメータの意味は次の通りです。

| パラメータ名 | 意味 |
|----|----|
| max_depth | 木の最大深度 |
| eta | 学習率 |
| objective | 学習目的 |
| num_class | クラス数 |

'objejective'に学習目的(回帰、分類等)を指定します。
今回は多クラス分類なので'multi:softmax'を指定しています。

詳細は公式に詳しく載っています。
[XGBoost Parameters &#8212; xgboost 1.1.0-SNAPSHOT documentation](https://xgboost.readthedocs.io/en/latest/parameter.html)

## [1-7] 学習
`num_round`は学習回数です。

```python
num_round = 10
bst = xgb.train(param, dtrain, num_round)
```

## [1-8] 予測
```python
dtest = xgb.DMatrix(test_x)
pred = bst.predict(dtest)
```

## [1-9] 精度の確認
scikit-learnの`accuracy_score`で正解率を確認します。

```python
from sklearn.metrics import accuracy_score

score = accuracy_score(test_y, pred)
print('score:{0:.4f}'.format(score))
# 0.9667
```

## [1-10] 重要度の可視化
どの特徴量が予測結果に寄与したのかを可視化します。

```python
xgb.plot_importance(bst)
```
![Feature_Importance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345798/0a499c8c-7d8f-9cd0-ab57-30d5d2a130d9.png)


# [2] 学習中のバリデーションとアーリーストッピング

検証用データを用いた学習中のバリデーションと、アーリーストッピング(学習の打ち切り)も簡単に行うことができます。

## [2-1] データの分割
学習用データの一部を検証用データとして使用します。

```python
train_x, valid_x, train_y, valid_y = train_test_split(train_x, train_y, test_size=0.2, shuffle=True)
```
## [2-2] DMatrixの作成
```python
dtrain = xgb.DMatrix(train_x, label=train_y)
dvalid = xgb.DMatrix(valid_x, label=valid_y)
```

## [2-3] パラメータの追加
バリデーションを行う場合には'eval_metric'をパラメータに追加します。'eval_metric'には、評価指標を指定します。

```python
param = {'max_depth': 2, 'eta': 0.5, 'objective': 'multi:softmax', 'num_class': 3, 'eval_metric': 'mlogloss'}
```

## [2-4] 学習
evallistにバリデーションで監視するデータを指定します。検証用データの名称は'eval'、学習用データの名称は'train'を指定します。

xgb.trainの引数として`early_stopping_rounds`を追加しています。`early_stopping_rounds=5`は5回連続して評価指標が改善しなかったら学習を中断する、ことを意味しています。

```python
evallist = [(dvalid, 'eval'), (dtrain, 'train')]
num_round = 10000
bst = xgb.train(param, dtrain, num_round, evallist, early_stopping_rounds=5)
# [0]	eval-mlogloss:0.61103	train-mlogloss:0.60698
# Multiple eval metrics have been passed: 'train-mlogloss' will be used for early stopping.
# 
# Will train until train-mlogloss hasn't improved in 5 rounds.
# [1]	eval-mlogloss:0.36291	train-mlogloss:0.35779
# [2]	eval-mlogloss:0.22432	train-mlogloss:0.23488
# 
# 〜〜〜 途中省略 〜〜〜
# 
# Stopping. Best iteration:
# [1153]	eval-mlogloss:0.00827	train-mlogloss:0.01863
```

## [2-5] 検証結果の確認

```python
print('Best Score:{0:.4f}, Iteratin:{1:d}, Ntree_Limit:{2:d}'.format(
     bst.best_score, bst.best_iteration, bst.best_ntree_limit))
# Best Score:0.0186, Iteratin:1153, Ntree_Limit:1154
```

## [2-6] 予測
検証結果のうち最も結果が良かったモデルで予測を行います。

```python
dtest = xgb.DMatrix(test_x)
pred = ypred = bst.predict(dtest, ntree_limit=bst.best_ntree_limit)
```

# 終わりに
pandasのDataFrame, Seriesが使えるので、今まで機械学習をやってきた人にとって敷居は低いように感じられました。

今回試したのは多クラス分類ですが、二値分類や回帰にも使用できるので、様々な場面で使うことができるでしょう。