Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

Pythonのscikit-learnでRandomForest vs SVMを比較してみた

Random Forest

Random Forest

Random Forest

Random Forestとは

機械学習の方法論の一つで決定木ベースの集団学習アルゴリズムを取り入れたものです。説明変数の依存が少ないことや学習が高速であることが特徴として挙げられています。英語サイトの方で特徴として紹介されているRFの内容について記述します。

Features
  • 大きなデータに対して効率よく処理される。
  • 変数の削除をすることなく入力した数千の変数を扱う事ができる。
  • どの変数が分類に対して重要なのかを計算して与えてくれる。
  • 木の構築処理中に一般的なエラーの偏りの無い計算を生成する。
  • 高い割合でデータが誤っている時に誤りのデータを計算し、精度を保つ効果的な手法を持っている。
  • アンバランスなデータが与えられたクラス群の中でエラーのバランスに対する手法を持っている。
  • 生成された木は今後他のデータに適用させるために保存する事ができる。
  • 変数とクラスタリング間の関係性に関する情報を計算する。
  • クラスタリングに利用される隣接するケースを計算する。
  • 上の特性はラベリングやクラスタリングされていないデータやはずれ値に対しても拡張する事ができる。
  • 変数の相互作用を発見するための実験的な方法を推薦する。
Remarks
  • RFではoverfitは存在しない。
  • RFは複数の木として処理できるし、それは処理速度が速い。
  • 5万のデータと100の変数を持ったデータに対して、100個の木に割り当て、800Mhzのマシンで11分で処理が終わる。
  • RFではCross-Validationをする必要がない。out-of-bag (oob) エラー計算がその代わりとなる。
テキストデータ分類器の比較

このPFD-PaperによるとRFがマクロ平均のF値において最も精度が高いと言われていますが、どんなデータに対しても精度が高いとは言えないと思います。画像引用 : 図6 : 10のテーマにおけるマクロ平均のF1 値の平均プロット

Mac × Pythonで利用する

env

pythonは2.7を利用します。元々設定されていたPythonは2.6.7だったのですが、install時に色々と問題がでてきたので2.7に変えます。複数Pythonを使い分けるにはpython_selectというコマンドがあったのですが、現在は使えなくなっているようです。その代わりにport select --setで切り替えます。

$ sudo port select --set python python27
$ python -V
Python 2.7.2
Package

MacOSX 10.6.8とPythonでRandomForestを利用するには以下のパッケージが必要になります。
※scikit-learnにはRandomForest以外のアルゴリズムも含まれているので、その他の機械学習ツールを使いたい場合も以下を参考にすると設定できると思います。

設定手順

※easy_installで上のpackageをinstallを試みましたが、scipyのinstallで失敗します。UMFPACKというパッケージが存在しないことが原因のようですが、直接的な解決方法が分かりませんでした。もし直接的な解決方法をご存知の方いましたら教えていただけると助かります。

$ sudo easy_install-2.7 scipy 
Searching for scipy
Reading http://pypi.python.org/simple/scipy/
Reading http://www.scipy.org
Download error: [Errno 61] Connection refused -- Some packages may not be found!
Reading http://sourceforge.net/project/showfiles.php?group_id=27747&package_id=19531
Reading http://new.scipy.org/Wiki/Download
Best match: scipy 0.11.0
Downloading http://pypi.python.org/packages/source/s/scipy/scipy-0.11.0.zip#md5=40b700ddde9ddab643b640fff7a9d753
Processing scipy-0.11.0.zip
Running scipy-0.11.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-7aUbZx/scipy-0.11.0/egg-dist-tmp-phUwYf
Running from scipy source directory.
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/numpy-1.6.2-py2.7-macosx-10.6-x86_64.egg/numpy/distutils/system_info.py:470: UserWarning: 
    UMFPACK sparse solver (http://www.cise.ufl.edu/research/sparse/umfpack/)
    not found. Directories to search for the libraries can be specified in the
    numpy/distutils/site.cfg file (section [umfpack]) or by setting
    the UMFPACK environment variable.
  warnings.warn(self.notfounderror.__doc__)
error: None

間接的な解決方法として、ぐぐってみたら以下のようなサイトを見つけました。ScipySuperpackというものを利用してnumpy,matplotlib,scipyをinstallします。

ScipySuperpackのinstall.shを実行します。実行時に質問を聞かれますが、nで答えます。

$ curl -o install_superpack.sh "https://raw.github.com/fonnesbeck/ScipySuperpack/master/install_superpack.sh"
$ sh install_superpack.sh
Are you installing from a repository cloned to this machine (if unsure, answer no)? (y/n)
n 
Cloning Scipy Superpack
Cloning into ScipySuperpack...
remote: Counting objects: 452, done.
remote: Compressing objects: 100% (226/226), done.
remote: Total 452 (delta 240), reused 433 (delta 221)
Receiving objects: 100% (452/452), 332.41 MiB | 1.11 MiB/s, done.
Resolving deltas: 100% (240/240), done.
(略)

Reading http://pypi.python.org/simple/patsy/
Reading https://github.com/pydata/patsy
Best match: patsy 0.1.0
Downloading http://pypi.python.org/packages/source/p/patsy/patsy-0.1.0.zip#md5=4be1210fb5050fb83b6859fe7706b339
Processing patsy-0.1.0.zip
Running patsy-0.1.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-u6TbHU/patsy-0.1.0/egg-dist-tmp-CXu4_o
no previously-included directories found matching 'doc/_build'
zip_safe flag not set; analyzing archive contents...
Adding patsy 0.1.0 to easy-install.pth file

Installed /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/patsy-0.1.0-py2.7.egg
Cleaning up
Done
RandomForestの実行

RFの実行にlibsvmのサンプルデータでもあるirisを使います。LIBSVM Data: Classification, Regression, and Multi-label はてなブックマーク - LIBSVM Data: Classification, Regression, and Multi-label データに付けられたlabelとfeatureをそれぞれPythonのRandomForestClassifierに渡せるように分解し、学習データと評価データを用意します。irisは150個のサンプルデータなので75個ずつに振り分けられます。学習データをfitさせ、評価データでpredictさせます。実行してみた結果としては71/75を正確にpredictできていたので、Accuracyは94.6%でした。処理時間は0.36s user 0.17s system 99% cpu 0.536 totalと出ました。以下はテスト用のコードです。

$ wget http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/iris.scale
$ time python rf.py
predict ok id = 0
predict ok id = 1
predict ok id = 2
predict ok id = 3
predict ok id = 4
predict ok id = 5
predict ok id = 6
predict ok id = 7
predict ok id = 8
predict ok id = 9
predict ok id = 10
predict ok id = 11
predict ok id = 12
(略)
predict miss id = 60
predict miss id = 61
predict ok id = 62
predict miss id = 63
predict ok id = 64
(略)
python rf.py  0.36s user 0.17s system 99% cpu 0.536 total
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re
from sklearn.ensemble import RandomForestClassifier

training_label = []
training_data = []
predict_label = []
predict_data = []
num = 0

file = open( './iris.scale' , 'r' )
for line in file :
    line = line.rstrip()
    node = []
    label = re.search( r'^(.*?)\s', line ).group(1)
    for i in range(1,5) :
        try : 
            pattern = r'%s' % ( str( i ) + ':(.*?\s)' )
            match = re.search( pattern, line ).group(1)
            if match is None :
                node.append(0) 
            else:
                node.append(match)
        except AttributeError :
            node.append(0)
            continue
    if num % 2 == 0 :
        training_data.append( node )
        training_label.append( label )
    else :
        predict_data.append( node )
        predict_label.append( label )
    num = num + 1

predict_data = training_data
model = RandomForestClassifier()
model.fit(training_data, training_label)
output = model.predict(predict_data)

for i in range( 0,len( output ) ) :
    str = "ok" if( int( predict_label[i] ) == int( output[i] ) ) else "miss"
    print "predict %s id = %d" % ( str, i )
SVMの実行

同じ要領でSVMも実行してみました。kernelは線形を利用しています。結果としては68 / 75が正確にpredictされていてAccuracyは90.6%でした。処理時間は0.38s user 0.20s system 97% cpu 0.599 totalとなりました。以下にPythonのテストコードを載せます。

$ time python svm.py
predict ok id = 0
predict ok id = 1
predict ok id = 2
predict ok id = 3
predict ok id = 4
predict ok id = 5
predict ok id = 6
predict ok id = 7
predict ok id = 8
predict ok id = 9
predict ok id = 10
predict ok id = 11
predict ok id = 12
(略)
predict ok id = 37
predict miss id = 38
predict ok id = 39
predict ok id = 40
predict miss id = 41
predict ok id = 42
(略)
python svm.py  0.38s user 0.20s system 97% cpu 0.599 total
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re,numpy as np
from sklearn import svm

training_label = []
training_data = []
predict_label = []
predict_data = []
num = 0
file = open( './iris.scale' , 'r' )
for line in file :
    line = line.rstrip()
    node = []
    label = re.search( r'^(.*?)\s', line ).group(1)
    for i in range(1,5) :
        try : 
            pattern = r'%s' % ( str( i ) + ':(.*?\s)' )
            match = re.search( pattern, line ).group(1)
            if match is None :
                node.append(0) 
            else:
                node.append( float( match ) )
        except AttributeError :
            node.append(0)
            continue
    if num % 2 == 0 :
        training_data.append( node )
        training_label.append( label )
    else :
        predict_data.append( node )
        predict_label.append( label )
    num = num + 1

model = svm.libsvm.fit( np.array( training_data ), np.float64( np.array( training_label ) ), kernel='linear' )
output = svm.libsvm.predict( np.array( predict_data ), *model,  **{'kernel' : 'linear'} )

for i in range( 0, len(output) ) :
    str = "ok" if( int( predict_label[i] ) == int( output[i] ) ) else "miss"
    print "predict %s id = %d" % ( str, i )

比較のまとめ

  • irisのデータに関してはRandomForestの方がAccuraryが良い結果が出た。
  • 75件の学習/評価データに対する処理速度は若干ながらRandomForestの方が速い事が分かった。