ランダム森、ランダムフォレスト、なんでもいいけど、要するに決定木を洗練するプログラムみたい。和訳するなら「乱数の森」、とかかっこいいんじゃない?(笑)
関連するキーワードは、自動学習、機械学習、集団学習、分類木、ブートストラップ、バギング、ってところでしょうか。
順を追って説明すると、とあるデータを使って決定木で分類ルールを探している。
こんな感じに。
library<span class="synSpecial">(</span>mvpart<span class="synSpecial">)</span> <span class="synComment">#ライブラリ読み込み</span> tree <span class="synStatement"><-</span> rpart<span class="synSpecial">(</span>chk~.<span class="synSpecial">,</span>data=tree.main<span class="synSpecial">,</span>method=<span class="synConstant">"class"</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"><-</span> predict<span class="synSpecial">(</span>tree<span class="synSpecial">,</span>newdata=tree.main<span class="synSpecial">,</span>type=<span class="synConstant">"class"</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"><-</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"><-</span> tree.main<span class="synSpecial">[</span>tr.num<span class="synSpecial">,]</span> <span class="synComment">#乱数の番号がある変数だけ抽出してサブセットtree.trainを作成</span> tree.test <span class="synStatement"><-</span> tree.main<span class="synSpecial">[</span>-tr.num<span class="synSpecial">,]</span> <span class="synComment">#上に選ばれなかったヤツはテスト用サブセットtree.test</span> tree <span class="synStatement"><-</span> rpart<span class="synSpecial">(</span>chk~.<span class="synSpecial">,</span>data=tree.train<span class="synSpecial">,</span>method=<span class="synConstant">"class"</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"><-</span> predict<span class="synSpecial">(</span>tree<span class="synSpecial">,</span>newdata=tree.test<span class="synSpecial">,</span>type=<span class="synConstant">"class"</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"><-</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"><-</span> predict<span class="synSpecial">(</span>tree.rf<span class="synSpecial">,</span>newdata=tree.main<span class="synSpecial">,</span>type=<span class="synConstant">"class"</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とか、描画してくれたらいいのに。
いや、俺がその方法を見つけられてないだけかもしれませんから、ご存知の方はご一報ください。
取りあえず、変数の重要度がわかるというのはメリット、メリット!