集団学習 (ensemble learning) は、決して精度が高くない複数の結果を統合・組み合わせることで精度を向上させる機械学習方法である。複数の結果の統合・組み合わせの方法としては、分類問題では多数決、数値の予測(回帰)問題では平均が多く用いられている。
集団学習では、異なる重み、あるいは異なるサンプルから単純なモデルを複数作成し、これらを何らかの方法で組み合わせることで、精度と汎化力を両立するモデルを構築する。
本稿では、集団学習方法による、回帰・分類のアルゴリズムバギング (bagging)、ブースティング (boosting)、ランダム森 (random forest) の基本概念およびこれらのRのパッケージと関数を紹介する。
機械学習の問題では、学習によって回帰・分類を行うシステムを学習機械と呼ぶ。文献によっては学習機械を仮説 (hypothesis)、分類器・識別器 (classifier)、学習器 (learner) とも呼ぶ。分類器は分類問題だけではなく、回帰分析、生存分析にも対応する学習機械の別名である。
2.バギング
バギング (bagging) の bagging は、bootstrap aggregating の頭の文字列を組み合わせた造語である。バギングは1996年 Breiman によって提案された[1]。
2.1 バギングのアルゴリズム
バギングは、与えられたデータセットから、ブートストラップ (bootstrap) と呼ばれているリサンプリング法による複数の学習データセットを作成し、そのデータを用いて作成した回帰・分類結果を統合・組み合わせる方法で精度を向上させる。ブートストラップサンプルはそれぞれ独立で、学習は並列に行うことができる。ブートストラップサンプルは、与えられたデータの経験分布とその推定量に基づいたリサンプリングにより得られたサンプルである。
バギングの大まかなアルゴリズムを次に示す。いま、 個の個体により構成された回帰・判別を目的とした教師付きデータがあるとする。
(1) 教師付きデータから復元抽出方法で
m 回抽出を行い、新たな訓練用サブデータセットを作成し、回帰・判別のモデル
h を構築する。
(2) ステップ(1)を
B 回繰り返し、回帰・判別のモデルを
B 個 {
hi |
i = 1 , 2 , … ,
B }構築する。
(3) 回帰の問題では、
B 個の平均値を結果とする。

(4) 判別の問題では、多数決をとる。
H (
x ) = argmax | {
i |
h i =
y } |
2.2 パッケージと関数
パッケージ ipred にバギング関数が実装されている。パッケージ ipred はCRANミラーサイトからダウンロードできる。パッケージ ipred の中のバギングの関数は bagging である。バギング関数 bagging は、回帰分析、分類分析、生存分析を前提とし、Breiman の方法に従っている[1]。
bagging(formula,data,nbagg=25…)
メインの引数の指定は、基本的には関数 rpart と同じである。引数 formula には目的変数と説明変数を指定し、data には用いるデータを指定する。引数 nbagg では、繰り返しの回数 を指定する。デフォルトは25になっている。関数 rpart のパラーメタの調整は引数 control と rpart.control を用いデフォルト値を替えることができる。
関数 print は、指定したモデルや nbagg などを返す。関数 summary は bagging の結果の要約を返すが、繰り返した毎回の結果を返すので、夥しい結果が返される。出力結果は引数 nbagg に依存する。
構築したモデルによるテストデータへの適応は、関数 predict を用いる。
パッケージ kernlab の中に用意されているデータ spam を用いて、関数 bagging の使用例を示す。パッケージ kernlab はCRANミラーサイトからダウンロードできる。
> library(kernlab);data(spam)
まず、学習用データとテスト用のデータセットを作成する。ここでは、データ spam から2500個体をランダムに選び学習用とし、その残りをテスト用とする。
> set.seed(50)
> tr.num<-sample(4601,2500)
> spam.train<-spam[tr.num,]
> spam.test<-spam[-tr.num,]
次に、作成した学習データを用いて学習を行い、その結果を用いてテストデータを用いて予測・判別を行う。
> spam.bag<- bagging(type~.,data=spam.train, nbagg=40)
> spam.bagp<- predict(spam.bag,spam.test[,-58],type= "class")
テストデータにおける判別・誤判別のクロス表を次に示す。
> (spam.bagt<- table(spam.test[,58], spam.bagp))
|
Spam.bagp |
|
nonspam |
spam |
nonspam |
1226 |
56 |
spam |
90 |
729 |
正しく判別できた比率(正解率)は次のコマンドで求めることができる。
> sum(diag(spam.bagt)) / sum(spam.bagt)
[1] 0.9305093
ブースティング (boosting) は、与えた教師付きデータを用いて学習を行い、その学習結果を踏まえて逐次に重みの調整を繰り返すことで複数の学習結果を求め、その結果を統合・組み合わせ、精度を向上させる。
3.1 ブースティングのアルゴリズム
ブースティングの中で最も広く知られているのは AdaBoost というアルゴリズムである。AdaBoost は、FreundとSchapier によって1996年に提案された[3]。その後、幾つかの変種 (Discrite AdaBoost、Gentle AdaBoost、Real AdaBoost、Logit AdaBoost、Modest AdaBoost など)が提案されている。そのアルゴリズムの詳細を説明する余裕がないので、大まかな共通点のみを次に示す。
(1) 重みの初期値
w 1iを生成する。
(2) 学習を行い重みの更新を繰り返す(
t = 1 , 2 , ・・・ ,
T )。
(a) 重み
w ti を用いて弱学習器

を構築する。
(b) 誤り率 α
t = err
t を計算する。
(c) 結果の信頼度 β
t を計算する。
(d) 重みを更新する。
w (t+1) i =
g (
w ti )
(3) 重み付き多数決で結果を出力する。2値判別の場合は
2値判別の場合は提案された幾つかの方法の大きい違いは、重みの初期値の与え方、信頼度の計算と重みの更新の方法である。
3.2 パッケージと関数
ブースティングを行うパッケージは boost、ada がある。パッケージ boost はCRANダウンロードミラーサイトからダウンロードでき、パッケージ ada は次のサイトからダウンロードできる。
https://cran.r-project.org/web/packages/ada/index.html
ローカルディスクにダウンロードした zip 形式で圧縮されたパッケージは、RGui のメニューの「パッケージ」⇒「ローカルにある zip ファイルからパッケージをインストール」をクリックし、zip ファイルを読み込むことでインストールできる。
パッケージ ada は、ブースティングの専用パッケージである。ブースティングを行う関数は ada である。関数 ada の書き式を次に示す。
ada(formula,iter=50,type = c("discrete","real","logit","gentle"),…
引数 formula は前節の関数 bagging と同じである。引数 iter は繰り返しの回数で、デフォルトは50になっている。引数 type では、4種類のブースティングの方法からひとつを指定する。デフォルトでは discrete が指定されている。
3.3 データと解析
本節でも spam データを用いることにする。 次に繰り返しの回数を20にした使用例を示す。
> library(ada)
> spam.ada<-ada(type~.,data=spam.train, iter=20)
学習結果を用いて、テストデータを当てはめるのには、関数 predict を用いる。関数 predict の書き式は基本的にはその他の回帰・判別関数と同じである。引数 type には、"vector" (予測値)、"prob" (確率)、 "both" (予測値と確率)などが指定できる。
> spam.adap<-predict(spam.ada, spam.test[,-58], type="vector")
> (spam.adat<-table(spam.test[,58], spam.adap))
|
Spam.adap |
|
nonspam |
spam |
nonspam |
1226 |
56 |
spam |
84 |
735 |
> sum(diag(spam.adat))/sum(spam.adat)
[1] 0.9333651
パッケージ ada には、作図関数 plot、varplot、pairs がある。関数 plot は学習の繰り返しの回数と誤り率との対応図を作成する。関数 plot にテストデータを引数として用いるとテストデータにおける繰り返しの回数と誤り率の対応図を作成することができる。また kappa 引数を真 (TRUE) とした場合は k 統計量 (kappa statistic; 多数決における一致性の指標) と学習の回数との対応関係図が作成される。
> plot(spam.ada,kappa=TRUE, spam.test[,-58],spam.test[,58])
図1 学習回数と誤り率および k 系統計量との関係
関数 varplot は、回帰・分類における変数の重要度を計算して図示する。現時点では若干不安定であり、更なるバージョンアップを期待する。
現時点のブースティング関数 boost、ada は、いずれも分類は2つクラスに限定されている。k 個のクラスに対応するためには若干のテクニックが必要である。関数 ada を用いた k クラスに対応する例が[4]に紹介されている。
ランダム森 (RF; random forest) は、バギングの提案者 Breiman により今世紀に提案された新しいデータ解析の方法である[4]。
4.1 ランダム森のアルゴリズム
RFのアルゴリズムを次に示す。
(1) 与えられたデータセットから 組のブートストラップサンプルを作成する。
(2) 各々のブートストラップサンプルデータを用いて未剪定の最大の決定・回帰木を作成する。ただし、分岐のノードはランダムサンプリングされた変数の中の最善のものを用いる。
(3) 全ての結果を統合・組み合わせ(回帰の問題では平均、分類の問題では多数決)、新しい予測・分類器を構築する。
バギングとRFの大きい違いは、バギングは全ての変数用いるが、RFでは変数をランダムサンプリングしたサブセットを用いることができるので、高次元データ解析に向いている。
ランダムサンプリングする変数の数Mはユーザが自由に設定することができる。Breiman は、Mは変数の数の正の平方根をと取ることを勧めている。
RFは、様々な工夫が施され、多くの長所を持っている。幾つかの長所は[5]で紹介している。
4.2 パッケージと関数
ランダム森の専用パッケージ randomForest は、CRANダウンロードミラーサイトからダウンロードできる。ランダム森のメイン関数は randomForest である。関数 randomForest の書き式を次に示す。
randomForest(formula, data=NULL,…, subset, na.action=na.fail)
関数 randomForest の引数やそれに関連する関数は、関数 bagging、ada より多い。表1に主な引数、表2には主な関連関数をまとめて示す。
表1 関数 randomForest の主な引数
引数 |
注 |
formula |
モデルの形式、y~x1+x3のように記する |
x、y |
説明変数と目的変数、formula の替わりに用いる |
data、subset |
用いるデータ |
na.action |
欠損値の表記型の指定 |
ntree |
木の数、デフォルト値は500である |
mtry |
木の生成に用いる変数の数、デフォルトでは、分類の場合は 、回帰の場合はn /3、n は変数の総数 |
importance |
変数の重要度 |
・・・ |
・・・ |
表2 関数 randomForest と関連する主な関数
関数 |
機能 |
print、summary |
結果の出力と要約の出力 |
plot |
木の数と誤り率との対応図 |
predict |
予測と判別 |
importance |
重要度の計算 |
varImpPlot |
分類に置ける変数の重要度のグラフ作成 |
classCenter |
分類におけるクラスの中心を求める |
MDSPlot |
MDSの散布図を作成する |
treesize |
用いた木のサイズ |
varUsed |
RFに用いられた変数の頻度 |
・・・ |
・・・ |
4.3 データと解析
前節で用意したデータ spam の学習データ spam.train を用いた randomForest の使用例を示す。
> library(randomForest)
> spam.rf<-randomForest(type~., data=spam.train,na.action="na.omit")
> print(spam.rf)
Call:
randomForest(formula = type ~ ., data = spam.train, na.action = "na.omit")
Type of random forest: classification
Number of trees: 500
No. of variables tried at each split: 7
OOB estimate of error rate: 5.16%
Confusion matrix:
|
nonspam |
spam |
class.error |
nonspam |
1459 |
47 |
0.031208500 |
spam |
82 |
912 |
0.08249497 |
結果のオブジェクトに、記録されている項目は関数 summary で確認できる。
> summary(spam.rf)
|
Length |
Class |
Mode |
call |
4 |
-none- |
call |
type |
1 |
-none- |
character |
predicted |
2500 |
factor |
numeric |
err.rate |
1500 |
-none- |
numeric |
confusion |
6 |
-none- |
numeric |
votes |
5000 |
matrix |
numeric |
oob.times |
2500 |
-none- |
numeric |
classes |
2 |
-none- |
character |
importance |
57 |
-none- |
numeric |
importanceSD |
0 |
-none- |
NULL |
localImportance |
0 |
-none- |
NULL |
proximity |
0 |
-none- |
NULL |
ntree |
1 |
-none- |
numeric |
mtry |
1 |
-none- |
numeric |
forest |
14 |
-none- |
list |
y |
2500 |
factor |
numeric |
test |
0 |
-none- |
NULL |
inbag |
0 |
-none- |
NULL |
terms |
3 |
terms |
call |
それぞれの項目は$***で返すことができる。例えば、上記で行ったRFは回帰問題であるか、それとも分類問題であるかに関する情報は次のコマンドで返す。
> spam.rf$type
[1] "classification"
木の数と誤判別率との対応関係は、$err.rate に記録される。関数plotを用いると $err.rate の折れ線グラフが作成される。次のコマンドの結果を図3に示す。
> plot(spam.rf)
図3 木の数と誤判別率との対応関係
図3には3つの折れ線があるが、凡例がないので、どの線が何を示しているかを読み取るためには、spam.rf$err.rate と対応付ける必要がある。
> spam.rf$err.rate
|
OBB |
nonspam |
spam |
[1,] |
0.10444444 |
0.09523810 |
0.11864407 |
[2,] |
0.10367893 |
0.08960177 |
0.12521151 |
<後略>
返された結果には、 OOB(out-of-bag) がある。OOBは交差確認・検証法 (cross-validation) における誤り率に対応するモデル評価の結果である。ランダム森では、作成したモデルの評価は、交差確認法および専用のテストデータセットを用いていない。ランダム森では、ブートストラップサンプルの3分の1をテスト用として外してモデルを作成し、外した3分の1を用いてテストを行う。OOBはこのテスト結果における誤判別率である。
ランダム森では、データセットにおける変数の重要度を計算する。変数の重要度は次のように返すことができる。関数 varImpPlot を用いてグラフで示すことができる。
> spam.rf$importance
|
MeanDecreaseGini |
make |
5.2107228 |
address |
6.1575212 |
all |
11.5373055 |
<中略> |
|
capitalLong |
68.3998362 |
capitalTotal |
52.9686201 |
> varImpPlot(spam.rf)
図4 変数の重要度 (Gini 係数)
構築したRFのモデルを用いて新しいデータについて回帰・分類を行うのには関数 predict を次のように用いる。
> spam.rfp<-predict(spam.rf, spam.test[,-58])
> (spam.rft<-table(spam.test[,58], spam.rfp))
Spam.rfp |
|
nonspam |
spam |
nonspam |
1242 |
40 |
spam |
73 |
746 |
> sum(diag(spam.rft))/sum(spam.rft)
[1] 0.946216
同じデータセットについてサポートベクトルマシンを用いて判別分析を行うとその正解率は0.9277で、ランダム森の結果より若干低い。
5.その他
本稿で紹介した集団学習のバギング、ブースティング、ランダム森が実用化された歴史は長くない。特にランダム森はその方法が提案されたのも約5年の年月しか経っていないので、その内容を扱っている和書は見当たらない。ランダム森の回帰・分類の精度は高く、その適応性もよいので、幅広い応用が期待できる。バギングとブースティングに関しては[5]が詳しい。
参考文献:
[1] Breiman, L. (1996); Bagging Predictors, Machine Learning, 24, 123-140.
[2] Breiman, L. (2001); Random Forests, Machine Learning, 45, 5-23.
[3] Freund, Y. and Schapier, R. E.(1996); Experiments with a new boosting algorithm, In Proceedings of ICML.
[4] Mark, C., Kjell, J. and George, M. (2005); ada: an R Package for Boosting,
https://www.jstatsoft.org/article/view/v017i02/v17i02.pdf
[5] 金 明哲(2005):決定木と集団学習, ESTRELA, No.133,62-67.
[6] 麻生英樹・津田宏治・村田昇(2003):パターン認識と学習の統計学、岩波書店