libsvm を JRuby で使う
JRuby SVM の実装
libsvm の配布物に添付されている libsvm.jar をクラスパスに置いたら、後は以下のコードだけで libsvm がそれなりに使えるようになるようです:
require 'java' module SVM SVM = JavaUtilities.get_proxy_class('libsvm.svm') Model = JavaUtilities.get_proxy_class('libsvm.svm_model') Parameter = JavaUtilities.get_proxy_class('libsvm.svm_parameter') Problem = JavaUtilities.get_proxy_class('libsvm.svm_problem') end
上記のコードは、Java のクラスを JRuby にとりこんでいるだけなので、本来自明な処理です。しかし、libsvm.jar では、クラスが Java のクラス名の命名規則に従っておらず、クラス名が小文字で始まっているという問題があります。これにより、JRuby の import や include_class で普通にクラスを取り込もうとすると、うまくいきません。Ruby の定数の命名規約違反になってしまうためです。
そこで、JRuby のメソッド include_class の定義を調べ、上記のようなコードにすればエラーなくクラスを取り込んでくれることが分かりました。
libsvm の構造を調べるに当たり、CRuby 用の libsvm バインディングである、Ruby SVM の RDoc ドキュメントが助けになりました。
クラス構造を調べる
この libsvm ライブラリの使い方は、Web 上にはそれほど書かれていません。しかし、libsvm の配布物に含まれている README と C ソース(コマンドラインツール (svm-scale, svm-train, svm-predict) の C ソース)を読むのが使い方を知る早道のようです。
README, C ソースに加えた補助的なデータとして、主要 Java クラスの構造を javap で調べてみました:
libsvm.svm
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm Compiled from "svm.java" public class libsvm.svm extends java.lang.Object{ static final java.lang.String[] svm_type_table; static final java.lang.String[] kernel_type_table; public libsvm.svm(); static libsvm.svm$decision_function svm_train_one(libsvm.svm_problem, libsvm.svm_parameter, double, double); public static libsvm.svm_model svm_train(libsvm.svm_problem, libsvm.svm_parameter); public static void svm_cross_validation(libsvm.svm_problem, libsvm.svm_parameter, int, double[]); public static int svm_get_svm_type(libsvm.svm_model); public static int svm_get_nr_class(libsvm.svm_model); public static void svm_get_labels(libsvm.svm_model, int[]); public static double svm_get_svr_probability(libsvm.svm_model); public static void svm_predict_values(libsvm.svm_model, libsvm.svm_node[], double[]); public static double svm_predict(libsvm.svm_model, libsvm.svm_node[]); public static double svm_predict_probability(libsvm.svm_model, libsvm.svm_node[], double[]); public static void svm_save_model(java.lang.String, libsvm.svm_model) throws java.io.IOException; public static libsvm.svm_model svm_load_model(java.lang.String) throws java.io.IOException; public static java.lang.String svm_check_parameter(libsvm.svm_problem, libsvm.svm_parameter); public static int svm_check_probability_model(libsvm.svm_model); static {}; }
libsvm.svm_model
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_model
Compiled from "svm_model.java"
public class libsvm.svm_model extends java.lang.Object implements java.io.Serializable{
libsvm.svm_parameter param;
int nr_class;
int l;
libsvm.svm_node[][] SV;
double[][] sv_coef;
double[] rho;
double[] probA;
double[] probB;
int[] label;
int[] nSV;
public libsvm.svm_model();
}
libsvm.svm_parameter
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_parameter Compiled from "svm_parameter.java" public class libsvm.svm_parameter extends java.lang.Object implements java.lang.Cloneable,java.io.Serializable{ public static final int C_SVC; public static final int NU_SVC; public static final int ONE_CLASS; public static final int EPSILON_SVR; public static final int NU_SVR; public static final int LINEAR; public static final int POLY; public static final int RBF; public static final int SIGMOID; public static final int PRECOMPUTED; public int svm_type; public int kernel_type; public int degree; public double gamma; public double coef0; public double cache_size; public double eps; public double C; public int nr_weight; public int[] weight_label; public double[] weight; public double nu; public double p; public int shrinking; public int probability; public libsvm.svm_parameter(); public java.lang.Object clone(); }
libsvm.svm_problem
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_problem
Compiled from "svm_problem.java"
public class libsvm.svm_problem extends java.lang.Object implements java.io.Serializable{
public int l;
public double[] y;
public libsvm.svm_node[][] x;
public libsvm.svm_problem();
}
これから
使用例などもあとで書くかもしれません。geotools.rb と同じく、素のラッパの上に、グッドラッパを目指すラッパを作っていくかもしれません。