ランダム森(Random Forest)

ランダム森、ランダムフォレスト、なんでもいいけど、要するに決定木を洗練するプログラムみたい。和訳するなら「乱数の森」、とかかっこいいんじゃない?(笑)

関連するキーワードは、自動学習、機械学習、集団学習、分類木、ブートストラップ、バギング、ってところでしょうか。

順を追って説明すると、とあるデータを使って決定木で分類ルールを探している。
こんな感じに。

 library<span class="synSpecial">(</span>mvpart<span class="synSpecial">)</span> <span class="synComment">#ライブラリ読み込み</span>
tree <span class="synStatement">&lt;-</span> rpart<span class="synSpecial">(</span>chk~.<span class="synSpecial">,</span>data=tree.main<span class="synSpecial">,</span>method=<span class="synConstant">&quot;class&quot;</span><span class="synSpecial">)</span> <span class="synComment">#tree.mainというデー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BF%A5%BB%A5%C3%A5%C8">タセット</a>に入っているchk変数を予測する分類木の作成</span>
print<span class="synSpecial">(</span>tree<span class="synSpecial">)</span> <span class="synComment">#木の描画</span>
judge <span class="synStatement">&lt;-</span> predict<span class="synSpecial">(</span>tree<span class="synSpecial">,</span>newdata=tree.main<span class="synSpecial">,</span>type=<span class="synConstant">&quot;class&quot;</span><span class="synSpecial">)</span> <span class="synComment">#同じデータを使って適合度をチェック</span>
table<span class="synSpecial">(</span>judge<span class="synSpecial">,</span>data$chk<span class="synSpecial">)</span> <span class="synComment">#適合度テーブル</span>

こうすると、最後のテーブルは

 judge     FTK Normal
FTK      <span class="synConstant">15</span>      <span class="synConstant">2</span>
Normal   <span class="synConstant">29</span>   <span class="synConstant">1890</span>

こんな感じになって、1936件のデータのうち、15+1890=1905件、約98%の精度でフィットさせることができる、っていうことがわかる。

さて、データが多いときのメリットは、交差妥当性をチェックできること。
単純な方法は、データをランダムに分割して、例えば60%を学習用、残りの40%を予測用に使ったりする。

ソースはこうだ。

tr.num <span class="synStatement">&lt;-</span> sample<span class="synSpecial">(</span><span class="synConstant">1936</span><span class="synSpecial">,</span><span class="synConstant">1161</span><span class="synSpecial">)</span> <span class="synComment">#1〜1936の中から1161(約60%)の乱数を作成</span>
tree.train <span class="synStatement">&lt;-</span> tree.main<span class="synSpecial">[</span>tr.num<span class="synSpecial">,]</span> <span class="synComment">#乱数の番号がある変数だけ抽出してサブセットtree.trainを作成</span>
tree.test  <span class="synStatement">&lt;-</span> tree.main<span class="synSpecial">[</span>-tr.num<span class="synSpecial">,]</span> <span class="synComment">#上に選ばれなかったヤツはテスト用サブセットtree.test</span>
tree <span class="synStatement">&lt;-</span> rpart<span class="synSpecial">(</span>chk~.<span class="synSpecial">,</span>data=tree.train<span class="synSpecial">,</span>method=<span class="synConstant">&quot;class&quot;</span><span class="synSpecial">)</span> <span class="synComment">#学習用セットで分類木を作成</span>
print<span class="synSpecial">(</span>tree<span class="synSpecial">)</span> <span class="synComment">#作った木を見てみよう</span>
judge <span class="synStatement">&lt;-</span> predict<span class="synSpecial">(</span>tree<span class="synSpecial">,</span>newdata=tree.test<span class="synSpecial">,</span>type=<span class="synConstant">&quot;class&quot;</span><span class="synSpecial">)</span> <span class="synComment">#作った木をテスト用でーたに当てはめてみる</span>
table<span class="synSpecial">(</span>judge<span class="synSpecial">,</span>tree.test$chk<span class="synSpecial">)</span> <span class="synComment">#その適合度は</span>

この結果は例えば、

 judge    FTK Normal
FTK      <span class="synConstant">3</span>     <span class="synConstant">13</span>
Normal  <span class="synConstant">15</span>    <span class="synConstant">744</span>

こうなった。775件のデータのうち、96%(=(3+744)/775)をあてた、ってことだ。

さて、乱数の森(Random Forest,RF)はこういう分割をしなくても、自動的にもとのデータセットからいくつかの変数をランダムサンプリングし、そのサブ・データセットを大量に作り、それぞれで木を組み立てる。だから森ができるのね。その森の中で、判別が上手くいく変数にポイントをつけて、変数の重要度みたいなのを算出する。

ソースと結果です。

library<span class="synSpecial">(</span>randomForest<span class="synSpecial">)</span> <span class="synComment">#ライブラリ読み込み</span>
tree.rf <span class="synStatement">&lt;-</span> randomForest<span class="synSpecial">(</span>chk~.<span class="synSpecial">,</span>data=tree.main<span class="synSpecial">)</span> <span class="synComment">#全てのデー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BF%A5%BB%A5%C3%A5%C8">タセット</a>でランダムフォレスト!</span>
print<span class="synSpecial">(</span>tree.rf<span class="synSpecial">)</span> <span class="synComment">#結果出力</span>
tree.rf$importance <span class="synComment">#変数の重要度</span>
varImpPlot<span class="synSpecial">(</span>tree.rf<span class="synSpecial">)</span> <span class="synComment">#重要度のプロット</span>
Call<span class="synSpecial">:</span>
randomForest<span class="synSpecial">(</span>formula = chk ~ .<span class="synSpecial">,</span> data = tree.main<span class="synSpecial">)</span>
Type of random forest<span class="synSpecial">:</span> classification
Number of trees<span class="synSpecial">:</span> <span class="synConstant">500</span>
No. of variables tried at each split<span class="synSpecial">:</span> <span class="synConstant">3</span>
OOB estimate of  error rate<span class="synSpecial">:</span> <span class="synConstant">2.32</span>%
Confusion <span class="synType">matrix</span><span class="synSpecial">:</span>
FTK Normal class.error
FTK      <span class="synConstant">1</span>     <span class="synConstant">43</span> <span class="synConstant">0.977272727</span>
Normal   <span class="synConstant">2</span>   <span class="synConstant">1890</span> <span class="synConstant">0.001057082</span>

これによると、3変数からなる500本の木をつくって学習させたところ、97.7%の分類ができたよ、ってことになっている。
森で予測しているから、どういうルートで、っていうのがわからない=解釈できないみたいだけど、ここで作ったモデルから新しいデータに対する予測は、上でやったpredict関数でできるみたいで、

judge <span class="synStatement">&lt;-</span> predict<span class="synSpecial">(</span>tree.rf<span class="synSpecial">,</span>newdata=tree.main<span class="synSpecial">,</span>type=<span class="synConstant">&quot;class&quot;</span><span class="synSpecial">)</span>
table<span class="synSpecial">(</span>judge<span class="synSpecial">,</span>tree.main$chk<span class="synSpecial">)</span>
judge     FTK Normal
FTK      <span class="synConstant">33</span>      <span class="synConstant">0</span>
Normal   <span class="synConstant">11</span>   <span class="synConstant">1892</span>

元のデータに当てはめてみたら、こうなった。かなりの精度だ。

木が描けると、ストーリーができたりして、心理学分野なんかでは解釈につかえていいかなぁ、と思っていたのだけど、森になったらそうもいかないのかもしれない。精度の高い木トップ10とか、描画してくれたらいいのに。

いや、俺がその方法を見つけられてないだけかもしれませんから、ご存知の方はご一報ください。

取りあえず、変数の重要度がわかるというのはメリット、メリット!