LIBSVMの学習データを正規分布に従うようにスケーリングするスクリプト書いた
機械学習の1手法であるSVMのライブラリ「LIBSVM」の入力データを,標準正規分布に従うようにスケーリング(標準化)するPythonスクリプトを書いたので公開します.
ソースコード
使い方
ソースコード上部のコメントに書いてある通りです.
以下のような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使って実装しました.
使用上の注意
- 動作テストは行いましたが,バグが存在する可能性もあります.ご利用の際は自己責任でお願いします.
- はっきり言って糞コードです^^; ファイル2回読んだりしてますので,処理に時間がかかる場合があります.
一応目的の処理は果たしてくれるんですが,改善点があればじゃんじゃん指摘していただけるとありがたいです. - 以下の警告が出力されることがありますが,気にしないでください.
(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=1
とaxis=0
を指定しています.ddof
で自由度を.axis
でどの要素(軸)に対してスケーリングをするかを指定しています.