静かなる名辞

pythonとプログラミングのこと



ランダムフォレストとSVMの使い分け

 ランダムフォレスト(RandomForest)とSVM(Support Vector Machine)はよく比較される分類器です。でも、様々なシチュエーションで、けっきょくどちらを使うべきなのか、という指針はあまり見かけません。

 私は研究などで*1両者を使ってきて、それなりに両者のクセもわかるようになってきたので、「こんな感じで使い分ければ良いんじゃない?」という情報を簡単にまとめておきます。

 結論を先に言うと、

  • 次元数とデータ数が多いか?

 Yesならばランダムフォレスト
 NoならばSVM

  • データの軸に明確な意味があるか?

 Yesならば(どちらかといえば)ランダムフォレスト
 Noならば(どちらかといえば)SVM

  • 最後は両方試して選ぼう
  • ランダムフォレストは多芸だけどSVMはそうでもないよ

 こんな感じです。一つずつ説明していきます。

 目次

スポンサーリンク



次元数とデータ数

 低次元でデータが少なければSVM、高次元でデータが多ければランダムフォレストです。これは精度云々より計算コストの問題です。

 ランダムフォレストは実用的な精度を得ようとすると、ある程度木の本数を増やす必要があります(500~1000くらいが相場、データによってはもっと)。それだけ多量の計算を回す必要がある上、決定木の処理というのはそれなりに重くてGPGPUなどによる並列化の恩恵も受けづらい(なにせ本質的にIF文の森)ので、どうしてもコストが高く付きます。なので、簡単な問題であればあるほどSVMの方が安上がりです。

 ただし、SVMは計算量(オーダー)が重く、高次元で大規模データであればあるほど重くなります。厳密な定義は難しいようですが(カーネルアルゴリズムによっても変わるだろうし)、たとえば下記ページを見ると、 O(n\_samples^2 * n\_features) なんて計算量が出ています(あくまでも一例として示されています。もっと速い場合もあるとか書いてあるし)。

What is the computational complexity of an SVM? - Quora

 その点ランダムフォレストはもうちょっと色々マシなので*2、データや次元数が増えていくとどこかでSVMと逆転します。

軸の意味

 これについてはっきり断言してくれた文献をこれまでほとんど(まったくかも)見たことがないんですが、ぶっちゃけ一番重要なんじゃないですかね。計算コストのことは置いておいて性能の優劣を論じる場合、だいたい軸に意味があるかどうかで決まってくる印象です。

 軸の意味といっても釈然としない方もいるかもしれませんが、たとえば二次元空間上に適当な正規分布を二個置いて決定境界を描く、みたいな例がよくありますが、ああいうのが「軸に意味がない」ケースです。とにかく空間があって、その上でクラスタを形成しているのを選り分けるようなケース。

 一方、軸にもうちょっと明快な意味がある場合もあります。典型的な例はテキスト分類で使われるBoW(Bag of Words)で、これは単語の出現回数をそのままベクトルにしたものです。100000単語のボキャブラリがある文書集合は100000次元のベクトルになります。こういう例では、軸の意味は非常にはっきりします(BoWならその軸に対応する単語の出現回数)。

 ランダムフォレストは決定木ですから、つまるところ「この軸の値がこの範囲なら……」という処理を繰り返して分類を行います。だから軸に直行する分離境界しか引けないとか言われたりします。下のページを見ると、そのことはよくわかります。

Classifier comparison — scikit-learn 0.20.0 documentation

 だけど、それが即欠点という訳ではなく、かえってよく働くケースは多々あると思います。上述したBoWは実はランダムフォレストを使うと上手く分類できるデータの好例で、私があるタスクで使ったときは、BoW*3のデータを分類させたランダムフォレストはSVMに対して10%くらいの優位を叩き出していました。そしてSVMをいくらチューニングしてもランダムフォレストには追いつきませんでした。

 考えてみるとわかりますが、SVMは基本的に滑らかな分離超平面を引くようにできています。そう言うとなんとなく良さそうですが、千次元とか二千次元の滑らかな超平面を学習データから完全に学習するのは、はっきり言って無理難題です。データが少なかったりノイジーだったりするとなおさら無理で、どうやっても破綻します。それより、さっさと決定木を作ってしまった方が無理がない訳で。

 ただし、だからといってランダムフォレスト最強でSVMが駄目だ、ということを言いたい訳ではないのに注意してください。滑らかな分離超平面が必要なときはSVMの方が適しています。たとえば、テキスト分類でも、BoWという巨大な疎行列を扱うのではなく、word2vecやらdoc2vecやらを使って低次元で密な分散表現を得るというアプローチもあります。そして、そっちで作った特徴量だとSVMの方がランダムフォレストより有利になったりもします*4

 要するに、欲しいものは「滑らかな(軸に対して斜めだったり曲がってたりする)分離超平面」なのか、「軸に直交する分離超平面」なのかをちゃんと考えてあげる必要があるということです。もちろんある程度は融通が効くので、この通りやらなくてもある程度の性能は出ますが、最終的に性能を追い込もうとするとこの辺りのことがとても響いてきます。

最後は両方試して選ぼう

 まあ、正直言って「どちらかを選ぶ」というシチュエーションなら両方試して(交差検証でF値出して)軽くて性能が高い方選べば良いと思います。pythonならsklearnのインターフェースは統一されていますから、そんなに難しいことじゃありません。というか、そういう目的で便利に使う(色々試して最適な方策を決める)ためにsklearnなんかのライブラリが整備されているのだし、データサイエンス・機械学習は最終的にはトライアル&エラーになるのが普通なんじゃないでしょうか。もっと言えば、選択肢に載せるアルゴリズムをランダムフォレストとSVMに限定する必要もなく、行けそうなものは全部試せば良いと思います。

 ぶっちゃけ、アルゴリズムを選ぶ理論的な根拠なんてカッコつけ以上の意味はないんです。分類問題は評価指標が出るんだから、「やってみたらこれが一番良かったです」で根拠としては十分でしょう。

 ただし、アルゴリズムの特性がわかっていると、

  • 明らかに無駄な試行は減らせる。どう見てもでかすぎるデータにSVM使って一晩回し続けるとか
  • ある程度は挙動(結果)が予想できるようになる。やる前からだいたいこうなるだろう、と見当がつくので、その通りにならなかったらなにか失敗してるかもしれないとか、未知の現象が介在してるかもしれないとか、そういことがわかる*5
  • 色々な難癖を付けたがる人は多いので、理論武装は色々しておくに越したことはない

 こういうご利益はあるので、この記事も皆様の何らかのお役に立てば良いな、と思います。

ランダムフォレストは多芸

 ランダムフォレストには次のような能力があります。

  • OOB誤り率が計算できる。交差検証の代わりに使える。パラメータチューニングには十分
  • 特徴重要度が計算できる。これを特徴選択に使える
  • predict probabilityが自然に計算できる

 この辺が面白いからランダムフォレストが好きだ、という人はけっこう多いんじゃないでしょうか。実用的にも便利なので、これらを期待して使うシチュエーションもあると思います。

まとめ

 どっちが良いかはデータ次第、というのが結論です。機械学習やデータサイエンスは、データの性質(分布)さえわかっていれば、後は知識と経験とカンでやっても場合によってはなんとかなります*6

 まあ、そういう「知識と経験とカン」に依存する要素を減らそうということで今はニューラルネットワークが流行っている訳ですが、ランダムフォレストやSVMのようなアルゴリズムも実際にはまだまだ使われていると思うので、当分の間は「使い分け」を意識してあげることも大切だと思います。

*1:ったって卒研ですが

*2:一本の木を構築するのに選ぶデータ数や次元数をどうするかにもよるが、通常は O(\sqrt{n})くらいで済む。

*3:本当は幾らでもあるBoW風の特徴量のうちの幾つか。生BoWではない

*4:これも実際に経験しました。ちなみにBoW+RandomForestより分散表現+SVMの方が性能面では当然有利です。分散表現はここ数年流行ってるので、ランダムフォレストの重要性は相対的に低下したと思います

*5:ただし、これに頼りすぎると「よしよし思い通り上手く行ってるな」→実は上手く行ってないけどなかなか気づかない、というパターンにたまにハマる。なので気をつける必要がある。コンピュータは間違えないけど使う人間は普通に間違えるので、眉にたくさん唾を付けておくに越したことはない

*6:慣れるとパラメータもダロカンで決めて、一発で最適パラメタを探り当てちゃうとか(笑)