-Python- Random Forest

Random Forestはアンサンブル学習と呼ばれる学習法の1つです.アンサンブル学習は,いくつかの性能の低い分類器(弱仮説器)を組み合わせて,性能の高い1つの分類器を作る手法です.弱仮説器のアルゴリズムは決まっていないので,適宜選択します.アンサンブル学習は弱仮説器の以下の2つの生成方法によって分類が可能です.

  • バギング:学習データを抜けや重複を許して複数個のグループに分割し,学習データのグループ毎に弱仮説器を生成する手法.分類器は,各弱仮説器の出力した分類結果の多数決をとります.複数のグループに分割した学習グループに対して弱仮説器をそれぞれ生成します(一部の学習データグループに特化した弱生成器を組み合わせて性能の良い分類器(強仮説器)を作る).
  • ブースティング:複数の弱仮説器を用意し,重み付きの多数決で分類を実現する手法.それらの重みも学習によって決定します.難易度の高い学習データを正しく分類できる弱仮説器の判別結果が重視されるように重みを更新していきます.より難易度の高いデータを抽出しながら,難易度の高いデータを分類することに特化した分類器を順次生成する.
Random Forestとは,アンサンブル学習のバギングに分類されるアルゴリズムです.学習データ全体の中から重複や欠落を許して決定木(弱仮説器)を生成します.
Randam Forestは学習,判別の処理が高速で,学習データのノイズにも強いというメリットがあります.ただし,学習データが少ない場合はか学習となる傾向があるので,あまり利用しない方が良いとされています.

以前の投稿にあった,3と8の手書き数字の画像データを分類する分類器をRandom Forestで作成してみます.ソースコードを以下のように書き換えます.

# Import module
import numpy as np
from sklearn import datasets
from sklearn import tree
from sklearn import metrics
from sklearn import ensemble
 
# load digits data
digits = datasets.load_digits()
 
# Find the positions of 3 and 8 data
flag_3_8 = (digits.target == 3) + (digits.target == 8)
 
# Get 3 and 8 data
images = digits.images[flag_3_8]
labels = digits.target[flag_3_8]
 
# Make data of 3 and 8 one-dimensional
images = images.reshape(images.shape[0], -1)
 
# Generation of classifiers
n_samples = len(flag_3_8[flag_3_8])
train_size = int(n_samples * 3 / 5)
# classifier = tree.DecisionTreeClassifier()
classifier = ensemble.RandomForestClassifier(n_estimators=20, \
                                        max_depth=3, criterion="gini")
classifier.fit(images[:train_size], labels[:train_size])
 
# Performance calculation of classifier
expected = labels[train_size:]
predicted = classifier.predict(images[train_size:])
 
print('Accuracy: \n', \
      metrics.accuracy_score(expected, predicted))
print('\nConfusion matrix: \n',
      metrics.confusion_matrix(expected, predicted))
print('\nPrecision: \n', \
      metrics.precision_score(expected, predicted, pos_label=3))
print('\nRecall: \n', \
      metrics.recall_score(expected, predicted, pos_label=3))
print('\nF-measure: \n', \
      metrics.f1_score(expected, predicted, pos_label=3))
 
書き換えた箇所は,Import moduleにおいて,
from sklearn import ensemble
を追記したのと,Generation of clasifirsの箇所で
classifier = ensemble.RandomForestClassifier(n_estimators=20, \
                                        max_depth=3, criterion="gini")
と変更した箇所です(以前の記載はコメントアウトしてあります).
classifier = ensemble.RandomForestClassifier()で,Random Forestの分類器を生成しています.生成時にはパラメータを指定することが可能です.ここでは,n_estimatorsmax_depth,およびcriterionを指定しています.n_estimatorsは弱仮説器の数で,デフォルトでは10ですが,20としています.max_depthcriterionは弱仮説器に使っている決定木に関するパラメータで,樹木モデルの最大深さ(上記の例では3)と決定木のアルゴリズム(上記の例ではCART)を指定しています.

実行結果は,以下のようになります.
Accuracy: 
 0.9300699300699301
 
Confusion matrix: 
 [[66  9]
 [ 1 67]]
 
Precision: 
 0.9850746268656716
 
Recall: 
 0.88
 
F-measure: 
 
 0.9295774647887323
 
前回の投稿の決定きを使った場合と比べると,正答率が86.0%から93.0%になり性能が高くなっていることがわかります.
scimitar-learnを使うと,分類器生成のアルゴリズムの変更が非常に容易です.また,決定木からRandom Forestへアルゴリズムを変更すると分類器の性能が向上しました.