洋食の日記

洋食のことではなく、技術メモを書きます。たまにどうでも良いことも書きます。

LIBSVM/SVMLight形式のデータの読み込み/書き込みをするgemを公開した

はじめに

LIBSVM形式のデータセットファイルを読み込み、データとラベルをNMatrixで返すライブラリが欲しかったので、作成してgemパッケージを公開した。

libsvmloader | RubyGems.org | your community gem host

Pythonのsvmlight-loaderにお世話になっているので、リスペクトのつもりで「LibSVMLoader」としたけど、Wekaに同名のクラスがあった。Loaderと名付けたけど、svmlight-loaderと同じく書き込みもできる。

インストール

読み込んだデータやラベルをNMatrixで返すのでNMatrixに依存する。

$ gem install libsvmloader

使い方

読み込みにはload_libsvm_fileメソッドを、書き込みにはdump_libsvm_fileメソッドを用いる。ドキュメントはこちら

require 'libsvmloader'

# 分類タスクを読み込む場合:
# samplesは、サンプル数x次元数のfloat64のNMatrix
# labelsは、サンプル数x1のint32のNMatrix
samples, labels = LibSVMLoader.load_libsvm_file('hoge.t')

# 回帰タスクを読み込む場合:
# ※ラベルに相当するNMatrixのdtypeを指定できるのでfloat64として実数とする
# samplesは、サンプル数x次元数のfloat64のNMatrix
# target_valuesは、サンプル数x1のfloat64のNMatrix
samples, target_values = LibSVMLoader.load_libsvm_file('hoge.t', label_dtype: :float64)

# libsvmファイルの特徴ベクトルの添字が「0」から始まる場合:
samples, labels = LibSVMLoader.load_libsvm_file('hoge.t', zero_based: true)

# 書き込み:
LibSVMLoader.dump_libsvm_file('foo.t')

# 書き込み(特徴ベクトルの添字を「0」から始めたい場合):
LibSVMLoader.dump_libsvm_file('foo.t', zero_based: true)

線形SVMによる分類のサンプル

例として、libsvmloaderでデータを読み込んで、liblinear-rubyで線形SVMの訓練・テストをするのは以下の様になる。

require 'libsvmloader'
require 'liblinear'

# 訓練データを読み込む.
tr_samples, tr_labels = LibSVMLoader.load_libsvm_file('pendigits')

# 線形SVMによる分類器を訓練する.
Liblinear.quiet_mode
model = Liblinear.train(
  { solver_type: Liblinear::L2R_L2LOSS_SVC },
  tr_labels.to_flat_a,
  tr_samples.to_a
)

# テストデータを読み込む.
ts_samples, ts_labels = LibSVMLoader.load_libsvm_file('pendigits.t')

# テストデータのラベルを推定する.
pr_labels = ts_samples.to_a.map { |fv| Liblinear.predict(model, fv).to_i }

# 正解数をカウントする.
n_hits = pr_labels.map.with_index { |l, n| 1 if l == ts_labels[n] }.compact.sum

# Accuracyを出力する.
n_ts_samples = ts_labels.size
accuracy = 100.0 * (n_hits / n_ts_samples.to_f)
puts(format('Accuracy = %.4f%% (%d/%d)', accuracy, n_hits, n_ts_samples))

おわりに

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