読者です 読者をやめる 読者になる 読者になる

しろかい!

アプリ開発や機械学習などの開発Tips.

LIBSVMの学習データを正規分布に従うようにスケーリングするスクリプト書いた

Python 機械学習

機械学習の1手法であるSVMのライブラリ「LIBSVM」の入力データを,標準正規分布に従うようにスケーリング(標準化)するPythonスクリプトを書いたので公開します.

f:id:shun9167:20150122223252p:plain

ソースコード

ソースコードGistにあげておきました.

使い方

ソースコード上部のコメントに書いてある通りです.

以下のようなLIVSVMの入力データ(train.txt)があるとします.

-1 1:6.000000 2:148.000000 3:72.000000 4:35.000000 5:0.000000 6:33.599998 7:0.627000 8:50.000000
+1 1:1.000000 2:85.000000 3:66.000000 4:29.000000 5:0.000000 6:26.600000 7:0.351000 8:31.000000
-1 1:8.000000 2:183.000000 3:64.000000 4:0.000000 5:0.000000 6:23.299999 7:0.672000 8:32.000000

これを下記コマンドでスケーリングを実行します.

$ python libsvm_gaussian_scaler.py -i train.txt

すると,以下の2つのファイルが出力されます. * 入力ファイル名.out: スケーリング後の学習データのファイル. * 入力ファイル名.out.stats: 素性id毎に平均と標準偏差を保存したファイル(テストデータのスケーリング時に必要).

スケーリング後のファイル(train.txt.out)はこんな感じです.

-1 1:0.27734 2:0.18799 3:1.1211 4:0.72998 5:0.0 6:1.0967 7:0.44312 8:1.1533 
+1 1:-1.1094 2:-1.0811 3:-0.32031 4:0.40967 5:0.0 6:-0.2345 7:-1.1445 8:-0.62354 
-1 1:0.83203 2:0.89258 3:-0.80078 4:-1.1396 5:0.0 6:-0.86182 7:0.70215 8:-0.52979 

まあそれっぽい値になってると思います.

LIMSVMに付属のsvm-scaleについて

LIBSVMにはsvm-scaleというスケーリングを実行できるコマンドが用意されています.
このコマンドによるスケーリングでは,ある区間(普通 [0, 1] or [-1, 1])に全ての素性値が存在するようにスケーリングします.
しかし,今回は標準正規分布に従うようにスケーリングする必要がありました.
が,そのようなスクリプトはなかったので自分でPython使って実装しました.

使用上の注意

  1. 動作テストは行いましたが,バグが存在する可能性もあります.ご利用の際は自己責任でお願いします.
  2. はっきり言って糞コードです^^; ファイル2回読んだりしてますので,処理に時間がかかる場合があります.
    一応目的の処理は果たしてくれるんですが,改善点があればじゃんじゃん指摘していただけるとありがたいです.
  3. 以下の警告が出力されることがありますが,気にしないでください.
    (0で割った時に出る警告ですが,内部でちゃんと処理しています)
RuntimeWarning: invalid value encountered in true_divide
  return (a - mns) / sstd

余談

最近Pythonを書く機会が増えているのですが,ホント便利ですね.
Javaだと50行書かないといけない処理が10行ぐらいで書ける.マジで.
ライブラリが豊富で,まさか標準正規分布に従うスケーリングをしてくれるscipy.stats.zscoreなるものまで存在するとは思いませんでした^^;

ちなみにファイルを2回も読み込んでいるのは,1回目で素性数を確かめるためです.
LIBSVMの入力データは素性値の省略が許されているのですが,そこに対応するには僕の知識ではこうするしかありませんでした...
いい方法があれば是非ご教授願いますm(__)m

scipy.stats.zscore について

scipy.stats.zscoreを使えば一発でnumpy配列に対してスケーリングが行えます.
今回の実装では引数にddof=1axis=0を指定しています.ddofで自由度を.axisでどの要素(軸)に対してスケーリングをするかを指定しています.

参考