洋食の日記

「だ・である」調ではなく「です・ます」調で書きはじめれば良かったなと後悔してる人のブログです

SVMKitのSVM系分類器に事後確率を推定するメソッドを追加した

はじめに

SVMKitのSupport Vector MachineSVM)系の分類器であるSVCKernelSVCに、ロジスティック回帰と同様に事後確率を推定するpredict_probaメソッドを追加した。

svmkit | RubyGems.org | your community gem host

これにあわせて、Log-Lossを評価するクラスを追加した。そして、それを良い感じに動かすために、ラベル情報に整数を割り当ててベクトルにするLabelEncoderや、ラベル情報からOne-hot-vectorを生成するOneHotEncoderを追加した。

使い方

事後確率の推定には、SVMの識別関数の値をもとに、シグモイド関数のモデルを当てはめる手法を用いている(詳しくはdocumentのreferenceにある論文を参照)。SVMKitでは、Scikit-Learnにならって、コンストラクタにprobablity引数を追加したので、これをtrueにすると事後確率のためのモデルを計算する。

require 'svmkit'

# LIBSVM形式のデータを読み込む.
samples, labels = SVMKit::Dataset.load_libsvm_file('pendigits')
samples = Numo::DFloat.cast(samples)

# 線形SVMを定義する.事後確率の推定のためprobability引数にtrueを指定する.
svc = SVMKit::LinearModel::SVC.new(reg_param: 1.0, max_iter: 1000, probability: true, random_seed: 1) 

# 評価手法にLogarithmic Lossを用いる.
ev = SVMKit::EvaluationMeasure::LogLoss.new

# 10-交差検定で評価する.
kf = SVMKit::ModelSelection::StratifiedKFold.new(n_splits: 10, shuffle: true, random_seed: 1)
cv = SVMKit::ModelSelection::CrossValidation.new(estimator: svc, splitter: kf, evaluator: ev)
report = cv.perform(samples, labels)

# 結果を出力する
mean_logloss = report[:test_score].inject(:+) / kf.n_splits
puts("Mean log-loss: %.3f" % mean_logloss) 

これを実行すると、平均Log-Lossが出力される。

Mean log-loss: 0.293

マルチクラスなLog-Lossを計算するために、いわゆるLabelEncoderOneHotEncoderが必要になったので、これも追加した。

おわりに

0.2系も0.2.9にまで達したので、分類器がらみの実装はひとまず置いて、回帰を実装していこうと思う。リファクタリングできる箇所も多いが(基本的に確率的勾配降下法を用いていて共通化できるコードが多い)それもグッと我慢して、分類以外のタスクにも使えるようにすることを優先しよう、という思う。

つまらないものですが、よろしくお願い致します。