0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

機械学習パッケージmlrを使った順序関係があるカテゴリ分類(その5)

Last updated at Posted at 2020-08-06

1.はじめに

仕事では順序関係があるカテゴリ分類のデータを扱うことが多いので、Rのmlrパッケージを使った機械学習にチャレンジしてみました。
ちなみに、仕事はIT関係では全くないので、全くの素人分析屋です。

前回までです。
機械学習パッケージmlrを使った順序関係があるカテゴリ分類(その1)
機械学習パッケージmlrを使った順序関係があるカテゴリ分類(その2)
機械学習パッケージmlrを使った順序関係があるカテゴリ分類(その3)
機械学習パッケージmlrを使った順序関係があるカテゴリ分類(その4)

前回からXgboostを使っています。今回は回帰でやってみます。

2.データとタスクの定義

早速、タスクを定義していきます。
まずは、分類問題としてやってみます。
xgboostのクラス分類は0から始める必要があるため、1を引きます。

library(tidyverse)
library(xgboost)
library(mlr)
library(mlbench)
library(parallel) #detectCores()を使ってCPUコア数を取得する
library(parallelMap)
data(BostonHousing, package = "mlbench")
df = BostonHousing
df$medvC = cut(df$medv,breaks =3,labels =c(1,2,3))
n = nrow(df)
train.set = scan("train.txt")     #第1回目で保存したもの
test.set = setdiff(1:n, train.set)

df$medv = NULL
df$medvC=as.numeric(df$medvC)
task_BostonHousing = makeRegrTask(id = "BostonHousing", data = df, target = "medvC")
task_BostonHousing = createDummyFeatures(task_BostonHousing)
task_BH_train =subsetTask(task_BostonHousing ,subset =train.set )
task_BH_train

$>Read 354 items
$>Supervised task: BostonHousing
$>Type: regr
$>Target: medvC
$>Observations: 354
$>Features:
$>   numerics     factors     ordered functionals 
$>         14           0           0           0 
$>Missings: FALSE
$>Has weights: FALSE
$>Has blocking: FALSE
$>Has coordinates: FALSE

3.学習器の構築

makeLearner関数は、回帰なので"regr.xgboost"を指定します。

set.seed(123)
parallelStartSocket(detectCores())
regr.lrn = makeLearner("regr.xgboost", objective= "reg:linear")

$>Starting parallelization in mode=socket with cpus=8.

3.1評価関数の作成

予測した連続値から、クラスを分ける閾値の関数(SQWK)を作成します。

SQWKfun = function(x = seq(1.5, 2.5, by = 1), pred) {
  preds = pred$data$response
  true = pred$data$truth 
  cuts = c(min(preds), x[1], x[2],  max(preds))
  preds = as.numeric(Hmisc::cut2(preds, cuts))
  err = Metrics::ScoreQuadraticWeightedKappa(preds, true, 1, 3)
  return(-err)
}

SQWK = makeMeasure(id = "SQWK", minimize = FALSE, properties = c("regr"), best = 1, worst = 0,
  fun = function(task, model, pred, feats, extra.args) {
    return(-SQWKfun(x = seq(1.5, 2.5, by = 1), pred))
  })
parallelExport("SQWK", "SQWKfun")

$>Exporting objects to slaves for mode socket: SQWK,SQWKfun

4.ベイズ最適化を用いたハイパーパラメータのチューニング

まず、調整するハイパーパラメータの範囲を設定します。
リサンプリングは交差検証法を用います。
なお、第2回で用いた層化抽出法は回帰タスクでは使えません。

ps = makeParamSet(
  
  makeNumericParam("eta", lower = 0.01, upper = 0.3),
  makeNumericParam("colsample_bytree", lower = 1, upper = 2, trafo = function(x) x/2),
  makeIntegerParam("min_child_weight", lower = 1, upper = 20),
  makeIntegerParam("nrounds", lower = 10,  upper = 300),
  makeIntegerParam("max_depth", lower = 1, upper = 8)
  )
rdesc = makeResampleDesc("CV",iters = 7)

ベイズ最適化によるハイパーパラメータのチューニングを実行します。

library(Hmisc)
library(mlrMBO)
mbo.ctrl = makeMBOControl()
mbo.ctrl = setMBOControlTermination(mbo.ctrl, iters = 5)
ctrl = makeTuneControlMBO( mbo.control = mbo.ctrl)
res6 = tuneParams(learner = regr.lrn, 
                     task = task_BH_train, 
                     resampling =rdesc , 
                      par.set = ps, 
                      control = ctrl, 
                      show.info = TRUE, 
                     measures = SQWK)

res6
parallelStop()

$>[Tune] Started tuning learner regr.xgboost for parameter set:
$>
$>With control class: TuneControlMBO
$>Imputation value: -0
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 20.
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 1.
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 1.
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 1.
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 1.
$>Mapping in parallel: mode = socket; level = mlrMBO.feval; cpus = 8; elements = 1.
$>[Tune] Result: eta=0.0869; colsample_bytree=0.794; min_child_weight=15; nrounds=137; $>max_depth=7 : SQWK.test.mean=0.7915147
$>Tune result:
$>Op. pars: eta=0.0869; colsample_bytree=0.794; min_child_weight=15; nrounds=137; max_depth=7
$>SQWK.test.mean=0.7915147
$>Stopped parallelization. All cleaned up.

結果は、eta=0.0869; colsample_bytree=0.794; min_child_weight=15; nrounds=137; max_depth=7のときにkappaが0.79となりました。
第3回の結果が0.78でしたので、ほぼ同じです。

5.最適なパラメータの設定とクラス分け閾値の最適化

交差検証法を使って、SQWK関数を使ったクラス分けの最適な閾値を探します。

regr.lrn = setHyperPars(regr.lrn, par.vals = res6$x)
cv = crossval(regr.lrn, task_BH_train, iter = 7, measures = SQWK, show.info = TRUE)
parallelStop()
optCuts = optim(seq(1.5, 2.5, by = 1), SQWKfun, pred = cv$pred)
optCuts$par

$>Resampling: cross-validation
$>Measures:             SQWK      
$>[22:24:44] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 1:    0.7269116 
$>[22:24:44] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 2:    0.6842105 
$>[22:24:45] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 3:    0.7252747 
$>[22:24:45] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 4:    0.7017544 
$>[22:24:45] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 5:    0.7403055 
$>[22:24:46] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 6:    0.6921529 
$>[22:24:46] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[Resample] iter 7:    0.7660819 

$>Aggregated Result: SQWK.test.mean=0.7195274
$>[1] 1.388531 2.380424

交差検証の結果は0.72でした。
クラス1: -inf - 1.388531
クラス2: 1.388531 - 2.380424
クラス3: 2.380424 - inf
に閾値が最適化されました。

6.テストデータによる評価

それでは、準備ができたので学習を実行し、テストデータによる評価を行います。

library(Metrics)
fit6 = train(regr.lrn, task_BH_train)
testTask =subsetTask(task_BostonHousing,subset =test.set )
pred = predict(fit6, testTask)
preds = as.numeric(Hmisc::cut2(pred$data$response, c(-Inf, optCuts$par, Inf)))
ScoreQuadraticWeightedKappa(preds,pred$data$truth)
table(pred$data$truth,preds)

$>[22:28:30] WARNING: amalgamation/../src/objective/regression_obj.cu:170: reg:linear is now $>deprecated in favor of reg:squarederror.
$>[1] 0.804699
$>   preds
$>     1  2  3
$>  1 52 19  0
$>  2  5 54  3
$>  3  0  1 18

全体の評価関数であるkappaは0.80と大幅に向上しました。
kappaの指標は0.6でgood、0.8ではexcellentになります。
クラス3の誤分類率は、ランダムフォレストによる回帰の第3回の結果が5/19、偽陽性率が1/13であり、Xgboostである今回は、誤分類率 1/19、偽陽性率 3/21になったため、ランダムフォレストの場合と比べると、誤分類率は向上しましたが、偽陽性率は少し悪くなりました。クラス3の分類精度を重視すれば、Xgboostに分配があがるかもしれません。

7.総評

BostonHousingのデータを使って5回にわたり、順序関係があるカテゴリ分類として扱ってきましたが、結局のところ、モデルの違いよりも、回帰を使った分類問題にすることで、最も良い精度がでました。有名なXgboostがもっと精度が高くなることを期待したのですが、今回の結果では、ランダムフォレストとあまり違いは見られませんでした。

8.PyCaretを使ってみた

pythonには自動的に機械学習モデルを比較してくれるPyCaretという便利なパッケージが最近リリースされたので、今回のBostonHousingの訓練データを使って比較してみました。
sankou.png

今までと同様に7分割交差検証法で比較した結果ですが、ランダムフォレストが一番でした。
ベストはkappa0.71と、ほぼこれまでの結果と同じような値になっています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?