6

私はSVMを初めて使用し、Pythonインターフェイスを使用してlibsvmを使用して、平均値と標準偏差を含むサンプルを分類しようとしています。しかし、私は無意味な結果を得ています。

このタスクはSVMに不適切ですか、それともlibsvmの使用にエラーがありますか?以下は、私がテストに使用している単純なPythonスクリプトです。

#!/usr/bin/env python
# Simple classifier test.
# Adapted from the svm_test.py file included in the standard libsvm distribution.
from collections import defaultdict
from svm import *
# Define our sparse data formatted training and testing sets.
labels = [1,2,3,4]
train = [ # key: 0=mean, 1=stddev
    {0:2.5,1:3.5},
    {0:5,1:1.2},
    {0:7,1:3.3},
    {0:10.3,1:0.3},
]
problem = svm_problem(labels, train)
test = [
    ({0:3, 1:3.11},1),
    ({0:7.3,1:3.1},3),
    ({0:7,1:3.3},3),
    ({0:9.8,1:0.5},4),
]

# Test classifiers.
kernels = [LINEAR, POLY, RBF]
kname = ['linear','polynomial','rbf']
correct = defaultdict(int)
for kn,kt in zip(kname,kernels):
    print kt
    param = svm_parameter(kernel_type = kt, C=10, probability = 1)
    model = svm_model(problem, param)
    for test_sample,correct_label in test:
        pred_label, pred_probability = model.predict_probability(test_sample)
        correct[kn] += pred_label == correct_label

# Show results.
print '-'*80
print 'Accuracy:'
for kn,correct_count in correct.iteritems():
    print '\t',kn, '%.6f (%i of %i)' % (correct_count/float(len(test)), correct_count, len(test))

ドメインはかなり単純なようです。2.5の平均がラベル1を意味することを知るように訓練されている場合、2.4の平均を見ると、最も可能性の高い分類としてラベル1を返すはずです。ただし、各カーネルの精度は0%です。どうしてこれなの?

いくつかの補足事項ですが、ターミナルでlibsvmによってダンプされたすべての冗長なトレーニング出力を非表示にする方法はありますか?libsvmのドキュメントとコードを検索しましたが、これをオフにする方法が見つかりません。

また、スパースデータセットのキーとして単純な文字列を使用したかったのです(例:{'mean':2.5、'stddev':3.5})。残念ながら、libsvmは整数のみをサポートしています。文字列の長整数表現(例:'mean' == 1109110110971110)を使用しようとしましたが、libsvmはこれらを通常の32ビット整数に切り捨てているようです。私が見る唯一の回避策は、各文字列を整数にマップする個別の「キー」ファイルを維持することです('mean' = 0、'stddev' = 1)。しかし、シリアル化された分類子と一緒に2番目のファイルを維持および永続化する必要があるため、明らかにそれは面倒です。誰かがもっと簡単な方法を見ていますか?

4

2 に答える 2

5

問題は、マルチクラス予測と確率推定を組み合わせることから来ているようです。

確率推定を行わないようにコードを構成すると、実際には機能します。たとえば、次のようになります。

<snip>
# Test classifiers.
kernels = [LINEAR, POLY, RBF]
kname = ['linear','polynomial','rbf']
correct = defaultdict(int)
for kn,kt in zip(kname,kernels):
  print kt
  param = svm_parameter(kernel_type = kt, C=10) # Here -> rm probability = 1
  model = svm_model(problem, param)
  for test_sample,correct_label in test:
      # Here -> change predict_probability to just predict
      pred_label = model.predict(test_sample)
      correct[kn] += pred_label == correct_label
</snip>

この変更により、次のようになります。

--------------------------------------------------------------------------------
Accuracy:
        polynomial 1.000000 (4 of 4)
        rbf 1.000000 (4 of 4)
        linear 1.000000 (4 of 4)

トレーニング セットのデータを2 倍にする (つまり、各データ ポイントを 2 回含める)場合、確率推定による予測は機能します。ただし、モデルをパラメーター化して、確率を使用したマルチクラス予測が元の 4 つのトレーニング ポイントだけで機能するようにする方法を見つけることができませんでした。

于 2010-04-03T04:25:06.173 に答える
3

これを行う別の方法に興味がある場合は、次のようにすることができます。この方法は理論的にはより健全ですが、それほど単純ではありません。

mean や std と言うと、何らかの形で分布していると想定しているデータを指しているように見えます。たとえば、観測者のデータはガウス分布です。その後、Symmetrised Kullback-Leibler_divergenceをこれらの分布間の距離測定として使用できます。次に、k-nearest neighborなどを使用して分類できます。

2 つの確率密度 p と q の場合、p と q が同じ場合にのみ KL(p, q) = 0 になります。ただし、KL は対称ではないため、適切な距離測定を行うために、次のように使用できます。

距離(p1, p2) = KL(p1, p2) + KL(p1, p2)

ガウスの場合、KL(p1, p2) = { (μ1 - μ2)^2 + σ1^2 - σ2^2 } / (2.σ2^2) + ln(σ2/σ1) です。(私はここからそれを盗みました。ここでは、偏差も見つけることができます:)

簡単に言えば:

(mean, std, class) タプルと新しい p = (mean, std) ペアのトレーニング セット D が与えられた場合、距離 (d, p) が最小である D 内の q を見つけ、そのクラスを返します。

分類の方法はそれほど恣意的ではないため、複数のカーネルを使用する SVM アプローチとして、私にはそれがより良いと感じています。

于 2010-04-02T21:44:19.627 に答える