lightgbmで多クラス分類を試す

# はじめに
この記事はlightgbmを使って多クラス分類を試してみたい方にむけた内容となっています。notebook環境で公開データセットを使ってコマンドのみで実行できるようにしています。

# ligthgbmとは
2017年にMicrosoft社によって開発された高速、軽量に動作する機械学習ライブラリです。勾配ブースティングをベースにしたモデルで、特徴量の重要度の計算、欠損値の扱いを自動で行い、回帰・分類問題にも対応したアルゴリズムです。類似のアルゴリズムとしてxgboostやcatboostと比較されますが、大規模なデータセットや高次元データに対して効果的に学習することができます。
# データセット
UCI Machine Learning Repositoryから白ワインの品質に関するデータセットを使用します
https://archive.ics.uci.edu/ml/datasets/Wine+Quality
こちらのデータセットは11個の特徴量(固定酸度、揮発性酸度、クエン酸、残糖、塩化ナトリウム、遊離二酸化硫黄、総二酸化硫黄、密度、pH、硫酸カリウム、アルコール度数)からワインの品質を7段階で予測するものになっています。
# ライブラリとデータのインポート
```python
# ライブラリのインポート
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import lightgbm as lgb
import matplotlib.pyplot as plt
```
次にデータの読み込みを行います
```python
data_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv'
df = pd.read_csv(data_url, sep=';')
df
```
![white_wine_dataframe.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071976/c0b572d1-4e56-987e-5ae1-b93702f5e24d.png)

読み込んだデータのデータ型の確認を行います。
```python
df.dtypes

# 実行結果 -> 
fixed acidity           float64
volatile acidity        float64
citric acid             float64
residual sugar          float64
chlorides               float64
free sulfur dioxide     float64
total sulfur dioxide    float64
density                 float64
pH                      float64
sulphates               float64
alcohol                 float64
quality                   int64
dtype: object
```
欠損値の確認を行います。
```python
df.isnull().sum()

# 実行結果 -> 
fixed acidity           0
volatile acidity        0
citric acid             0
residual sugar          0
chlorides               0
free sulfur dioxide     0
total sulfur dioxide    0
density                 0
pH                      0
sulphates               0
alcohol                 0
quality                 0
dtype: int64
```
教師データとなるワインの品質のラベルについて確認します。
```python
df['quality'].value_counts()

# 実行結果 -> 
6    2198
5    1457
7     880
8     175
4     163
3      20
9       5
Name: quality, dtype: int64
```
```python
plt.figure(figsize=(10, 6))
plt.hist(df['quality'], bins=6)
plt.show()
```
![Histogram of wine quality.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071976/aba8af0d-47fe-9be8-8aff-a11908e04e17.png)
データのヒストグラムを見ますと3から9までの数字になっています。lightgbmは教師データのラベルが0開始である必要があるため、学習時に修正する必要があります。
また、教師データの偏りが非常に大きいことが確認できます。多クラス分類における不均衡データの学習にはラベル数が少ないデータの学習が不十分になる特徴があり、ダウンサンプリングなどの対応が必要になりますが、今回はこのままデータを使用します。
# 学習
lightgbmによる学習と予測を行います。データセット全体を学習データとテストデータに8:2の割合で分割して、学習データで学習したモデルからテストデータの予測を行い、正答率を表示します。
```python
# 特徴量とラベルに分割
X = df.drop('quality', axis=1)
y = df['quality']

# クラスの値を調整
y -= 3

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LightGBM用のデータセットに変換
train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test)

# LightGBMのハイパーパラメータの設定
params = {
    'objective': 'multiclass', # 多クラス分類
    'num_class': 7, # クラスの数
    'metric': 'multi_logloss' # 損失関数にmulti_loglossを使用
}

# LightGBMモデルの学習
model = lgb.train(params, train_data, num_boost_round=1000, valid_sets=[train_data, test_data], early_stopping_rounds=10)

# テストデータでの予測
y_pred = model.predict(X_test)
y_pred_class = np.argmax(y_pred, axis=1) + 3 # 予測結果のクラスの値を調整
y_test += 3 # テストデータのクラスの値を調整
# 精度の評価
accuracy = accuracy_score(y_test, y_pred_class)
print('Accuracy:', accuracy)

# 実行結果 -> 
Accuracy: 0.6357142857142857
```
およそ63.57%の正答率となりました。
予測結果に寄与した特徴量の重要度を表示します。
```python
plt.figure(figsize=(10,6))
lgb.plot_importance(model)
plt.show()
```
![feature_importance.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071976/96e8e128-c7e1-d93d-2553-baba731fbc50.png)
重要度の数値から予測結果に寄与する特徴量間の比較ができます。
# まとめ
白ワインのデータセットからワインの品質を評価する多クラス分類問題についてlightgbmを用いて予測しました。正答率は63.57%となりました。今回はベースラインとして基本的な予測モデルを作成しました。
さらに予測精度を上げる方法として、データの前処理で不均衡データに対する方法やデータ拡張、半教師あり学習を用いたハイブリッドな手法、パラメータチューニングなど試せることはたくさんありますので、続きの記事を書いていきたいと思います。