LoginSignup
2
1

More than 5 years have passed since last update.

PythonでLIBSVMのカスタムカーネルを使う方法

Last updated at Posted at 2018-07-17

デフォルトのカーネルとはデータの扱い方が少し異なるので、備忘録も兼ねて

開発環境 : Windows 10 Pycharm 2018.1
LIBSVMは以下のページからダウンロードできます。インストール方法は他の記事を参考にしてください。
https://www.csie.ntu.edu.tw/~cjlin/libsvm/

カーネル

LIBSVMでは"linear", "polynomial", "RBF", "sigmoid", "precomputed"の5つのカーネルがパラメータ指定で使用できます。
precomputedを指定することで自分で定義したカーネルを使うことができます。
今回はカーネルとして一般化ガウス関数(GGD : Generalized Gaussian Distribution)使います。
GGDは形状が変化させられるガウス関数みたいな感じ, 詳しくはご自分でお願いします。
$\sigmaと\gamma$はパラメータです。

\begin{align}
K(x, y; \sigma, \gamma)&=\frac{g(\gamma)\gamma}{2\sigma\Gamma(1/\gamma)}\exp\left[\left(\frac{g(\gamma)||x-y||^2}{2\sigma^2}\right)^\gamma\right] \\
g(\gamma)&=\sqrt{\frac{\Gamma(3/\gamma)}{\Gamma(1/\gamma)}}
\end{align}
def ggd_kernel(x, y):
    sigma = パラメータ
    r = パラメータ
    beta = sigma * math.sqrt(math.gamma(1 / r) / math.gamma(3 / r))
    ggd = (r / (2 * beta * math.gamma(1 / r))) * np.exp(-(distance.cdist(x, y, metric="euclidean") / beta) ** r)
    return ggd

トレーニングデータ読み込み

1列目がラベル, 2列目以降が特徴量となるcsvなどを用意してください。
yにラベル, xに特徴量が入ります。

y, x = svm_read_problem("ファイル名")

LIBSVMを使う上でトレーニングデータの扱い方に注意が必要です。
ラベルがi個でprecomputedを使う場合は以下のようなフォーマットに変換しないとエラーが出ます。
この記事ではリストの中に辞書を入れています。
※GGDの計算結果はi×iの行列になるので下のようなフォーマットになります。

0 1 2 ・・・ i
0:1 1:data01 2:data02 ・・・ i:data0i
0:1 1:data11 2:data12 ・・・ i:data1i
0:1 1:datai1 2:datai2 ・・・ i:dataii

svm_read_problemで読み込んだ特徴量はリストの中に辞書が入った形で下の表のようになる。
フォーマットを合わせるために全てのデータの列を1つずらして, 0列に0:1を追加する。

0 1 ・・・ i
0:data01 1:data02 ・・・ i:data0i
0:data11 1:data12 ・・・ i:data1i
0:datai1 1:datai2 ・・・ i:dataii

トレーニングデータのみが入ったCSVファイルから上記のフォーマットに変換するプログラム

# 学習データ読み込み
y, x = svm_read_problem("hoge.csv")   
# svm_read_problemで読み込んだxはリストの中に辞書が入った形で[{0:data01, 1:data02, ..., i-1:data0i}]となるので, 表のフォーマットに変換する必要がある
# リスト[辞書]からデータフレームに変換
x = pd.DataFrame(x)

# データフレームから行列に変換
x_matrix = np.matrix(x)

# 学習データのGGDを計算
x_ggd = ggd_kernel(x_matrix, x_matrix)

# GGDの計算結果の格納リスト
x_list = []

# 行数分だけ回す
for i in range(x_ggd.shape[0]):
    # GGDの辞書(キーをつけるため)
    x_dict = {}
    # 列数分だけ回す
    for j in range(x_ggd.shape[1]):
        # keyに列数, valueにGGDのデータ
        x_dict[0] = i+1                 
        x_dict[j+1] = x_ggd[i][j]
    # 格納リストに辞書を追加
    x_list.append(x_dict)

学習

precomputedを使用するため, svm_problemのisKernelにTrue, SVMのパラメータに"-t 4"を指定する。

# 学習データ登録 isKernel=Trueでprecomputed
# yはラベル, x_listはGGDの計算結果(precomputed以外のカーネルの場合はトレーニングデータをそのまま入れる)
prob = svm_problem(y, x_list, isKernel=True)

# パラメータ設定
# SVCやSVRなど使う手法によって設定パラメータが異なるので注意
param = svm_parameter("-t 4")

# トレーニング
model = svm_train(prob, param)

# モデル保存
svm_save_model("model.txt", model)

分類・推定

分類・推定を行う際もカーネルの計算とデータフォーマットをそろえる必要がある。
※ソースコードではSVRを使用していたのでSVCなどではsvm_predictの部分が動かないかもしれません

# test_dataと特徴量のGGDを計算
ggd_predict = ggd_kernel(test_data, x_matrix)

ggd_predict_list = []

# 行数分だけ回す
for i in range(test_data.shape[0]):
    # GGDの辞書(キーをつけるため)
    test_data_dict = {}
    # 列数分だけ回す
    for j in range(x_ggd.shape[1]):
        # keyに列数, valueにGGDのデータ
        test_data_dict[0] = i+1           
        test_data_dict[j+1] = ggd_predict[i][j]
    # 格納リストに辞書を追加
    ggd_predict_list.append(test_data_dict)

predict_label, accuracy, dec_values = svm_predict(test_label, ggd_predict_list, model)

最後に

今回は使い方だけで例題を出していないので, 時間があれば例題を使って分類・推定をしたいと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1