XGBoostによる機械学習(Rを用いて実装)

P&Dアドベントカレンダー1日目！ついに始まりました！

今回は、卒業研究のために勉強した**XGBoost**の実装の流れについてまとめたいと思います。

#はじめに
私は研究室で主に、R言語を用いて機械学習やデータ分析等を行なっています。

機械学習には様々な手法がありますが、その中で今回私は**勾配ブースティング**を用いることとなりました。
そしてその勾配ブースティングをC++で実装して高速化した**XGBoost**を用いることにしました。

こちらに機械学習の代表的手法が載っていますのでぜひ参考にしてみてください。
私も記事を書く上でかなり参考にさせて頂いています。
[Qiita 代表的な機械学習手法一覧](https://**.com/tomomoto/items/b3fd1ec7f9b68ab6dfe2)

#XGBoostとは
複数の弱学習器を逐次的に(1つずつ順番に)構築して予測モデルを生成する手法をブースティング(Boosting)と言います。
新しい弱学習器を構築する際には、それまでの弱学習器の結果を利用して構築を行います。
結果が良くなかった(間違って識別された)場合、誤った学習データに対する重みを大きくします。
結果が良かった(正しく識別された)場合、正しい学習データに対する重みを小さくします。
そうすることで、次の弱学習器で間違えてしまった学習データを正しく識別できるようにします。

そのブースティングの中でも弱学習器を構築する際に行われる損失関数の最小化に勾配降下法を用いるものを勾配ブースティング(Gradient Boosting)と言います。


詳しくはこちらを参考にしてみてください。とてもわかりやすく説明されています。
[勾配ブースティングについてざっくりと説明する -About connecting the dots.]
(http://smrmkt.hatenablog.jp/entry/2015/04/28/210039)
[機械学習アルゴリズム~XGBoost -Rで学ぶベイズ統計学]
(http://rtokei.tech/machine-learning/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%80%9Cxgboost%E3%80%9C/)

そしてその勾配ブースティングをC++で実装して高速化したものが**XGBoost**と言います。
XGBoostは、eXtreme Gradient Boostingの略称です。

#XGBoostでの機械学習
早速ではありますが実装してみましょう！
既に用意されている「iris」のデータセットを使用してXGBoostの主な使い方を紹介したいと思います。

”セトナ(setona)”、"バーシクル(versicolor)"、"バージニカ(virginica)"の3種類のあやめ(花の一種)を、がく片長(Sepal Length)・がく片幅(Sepal Width)・花びら長(Petal Length)・花びら幅(Petal Width)の情報を用いて予測し分類するプログラムを作成します。


今回は「iris」の奇数番目のデータを学習データとして学習モデルを構築し、「iris」の偶数番目のデータを評価データとして評価を行います。


「iris」についての説明はこちらのページがわかりやすいと思います。
[フィッシャーのアイリスデータ]
(http://home.a00.itscom.net/hatada/ml/data/iris01.html)


####開発環境
R version 3.5.0
RStudio version 1.1.453

(最新のバージョンであれば問題ないはず)

###パッケージのインストールと呼び出し
```R
#パッケージのインストール
install.packages("xgboost") #xgboostを使用するためのパッケージ
install.packages("data.table") #data.table型を用いるのに必要

#パッケージ呼び出し
library(xgboost)
library(data.table)
library(Matrix) #dgCMatrix型を用いるのに必要
```

###「iris」データ形成
```R
#形成前
>iris

    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1            5.1         3.5          1.4         0.2     setosa
2            4.9         3.0          1.4         0.2     setosa
3            4.7         3.2          1.3         0.2     setosa
#(省略)
148          6.5         3.0          5.2         2.0  virginica
149          6.2         3.4          5.4         2.3  virginica
150          5.9         3.0          5.1         1.8  virginica


#irisデータを奇数・偶数に分割
odd.number <- 2*(1:75)-1 #1~150の奇数のみの数字
odd.data <- iris[odd.number,] #irisデータの奇数番目を代入
even.data <- iris[-odd.number,] #irisデータの偶数番目を代入

#再び併合しデータを整える
iris.data <- rbind(odd.data,even.data) #再び併合
y <- as.integer(iris.data[,5])-1 #目的変数を決定(今回の場合だと、あやめの種類"Species")
y <- as.data.frame(y) #上記のyをdata.frame型に変換
data <- transform(iris.data,y=y) #iris.dataにyを追加
data <- data[,-5] #irisデータの"Species"を削除


#形成後
>data

    Sepal.Length Sepal.Width Petal.Length Petal.Width y
1            5.1         3.5          1.4         0.2 0
3            4.7         3.2          1.3         0.2 0
5            5.0         3.6          1.4         0.2 0
7            4.6         3.4          1.4         0.3 0
9            4.4         2.9          1.4         0.2 0
#(省略)
142          6.9         3.1          5.1         2.3 2
144          6.8         3.2          5.9         2.3 2
146          6.7         3.0          5.2         2.3 2
148          6.5         3.0          5.2         2.0 2
150          5.9         3.0          5.1         1.8 2
```
XGBoostを用いて学習させるためには分類する”セトナ(setona)”、"バーシクル(versicolor)"、"バージニカ(virginica)"の3種類を整数値にしてirisデータのSpeciesと入れ替える必要があります。そのため、一度分割してから再び併合させています。(この後、再び学習データと評価データに分割させます。)

今回の場合だとセトナ(setona)は0、バーシクル(versicolor)は1、バージニカ(virginica)は2に変換されています。

###形成したデータを変換
```R
#データの分割
model.data <- data[1:75,] #学習データ
pre.data <- data[76:150,] #評価データ


#data.table型へ変換
model.data.dt <- data.table(model.data,keep.rownames=F)
pre.data.dt <- data.table(pre.data,keep.rownames=F)


#data.table型からxgb.dgCMatrixへ変換
model.data.mx <- sparse.model.matrix(y~.,model.data.dt)
model.data.dm <- xgb.DMatrix(model.data.mx,label=model.data.dt$y)

pre.data.mx <- sparse.model.matrix(y~.,pre.data.dt)
pre.data.dm <- xgb.DMatrix(pre.data.mx,label=pre.data.dt$y)
```
形成したデータを学習データ・評価データに分割後、XGBoostが読み込んでくれる形に変換させます。
変数dataの型は形成後だとdata.frame型になっています。
まずは変数dataをdata.table型に変換します。
次にxgb.dgCMatrixに変換することで準備完了です。

###XGBoostを用いて学習&評価
```R
#XGBoostパラメータ(今回は全てデフォルト値を採用)
params <- list(
  eta=0.3,
  gamma=0,
  max_depth=6,
  min_child_weight=1,
  max_delta_step=0,
  subsample=1,
  colsample_bytree=1,
  colsample_bylevel=1,
  lambda=1,
  alpha=0
)

#XGBoost
xgb.result <- xgb.train(params=params, data=model.data.dm, label=model.data.dt$y, num_class=3, objective="multi:softmax", booster="gbtree", nrounds=100, verbose=1)

#評価
pred <- predict(object=xgb.result,newdata=pre.data.dm)

for(i in 1:length(pred)){
  if(pred[i]==0) {pred[i]="setosa"}
  else if(pred[i]==1) {pred[i]="versicolor"}
  else {pred[i]="virginica"}
}

#評価結果
>table(even.data[,5],pred)

            pred
             setosa versicolor virginica
  setosa         25          0         0
  versicolor      0         23         2
  virginica       0          0        25
```

評価結果が出ましたね！
実際のirisデータの偶数番目のデータとXGBoostによって作成された予測モデルを用いて算出された予測結果のデータを比較してテーブル表示しています。
誤差が少し生じていますが、実装はできているみたいですね。

今回は代表的なパラメータをデフォルト値で設定しています。
値を変更することで評価結果が変化すると思うのでぜひ試してみてください。
こちらのページにパラメータに関する内容がまとめられています。
[XGBoost Parameters]
(https://xgboost.readthedocs.io/en/latest/parameter.html)
[xgboostのパラメータ]
(http://puyokw.hatenablog.com/entry/2015/04/11/040941)
[XGBoostやパラメータチューニングの仕方に関する調査]
(http://kamonohashiperry.com/archives/209)


次回はXGBoostのパラメータとランダムサーチによるパラメータチューニングに挑戦してみたいと思います！


実装の際に参考にさせていただきました。
[XGBoostの実装(R編]
(https://qiita.com/yh0sh/items/276dce93cd1e48d372d1)
[XgboostのRにおける具体例]
(http://puyokw.hatenablog.com/entry/2015/04/29/000557)
[Gradient Boosting Decision Treeでの特徴選択 in R]
(http://www.housecat442.com/?p=480)