Вычисление Ближайшего Соответствия к Паре Mean/Stddev С LibSVM

Я плохо знаком с SVMs, и я пытаюсь использовать интерфейс Python для libsvm для классификации образца, содержащего среднее и stddev. Однако я получаю бессмысленные результаты.

Действительно ли эта задача является несоответствующей для SVMs или является там ошибкой в моем использовании 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, но я не могу найти способ выключить это.

Кроме того, я хотел использовать простые строки в качестве ключей в моем редком наборе данных (например, {'означают ':2.5, 'stddev ':3.5}). К сожалению, libsvm только поддерживает целые числа. Я пытался использовать представление длинного целого строки (например, 'средний' == 1109110110971110), но libsvm, кажется, усекает их к нормальным 32-разрядным целым числам. Единственное обходное решение, которое я вижу, должно поддержать отдельный "ключевой" файл, который отображается, каждая строка к целому числу ('имейте в виду' =0, 'stddev' =1). Но очевидно это будет болью, так как я должен буду поддержать и сохранить второй файл наряду с сериализированным классификатором. Кто-либо видит более легкий путь?

6
задан Cerin 2 April 2010 в 15:38
поделиться

2 ответа

Проблема, похоже, возникает из-за комбинирования многоклассового предсказания с оценками вероятности.

Если вы сконфигурируете свой код так, чтобы он не делал оценок вероятности, он действительно работает , например:

<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)

Прогноз с оценками вероятности действительно работает, если вы удвоите данные в обучающий набор (т.е. включать каждую точку данных дважды). Однако я не смог найти способа параметризовать модель, чтобы мультиклассовое предсказание с вероятностями работало только с исходными четырьмя точками обучения.

5
ответ дан 16 December 2019 в 21:37
поделиться

Если вас интересует другой способ сделать это, вы можете сделать следующее. Этот способ теоретически более надежен, но не так прост.

Упоминая среднее и стандартное, создается впечатление, что вы ссылаетесь на данные, которые, по вашему мнению, каким-то образом распределяются. Например, данные, которые вы наблюдаете, распределены по Гауссу. Затем вы можете использовать симметричное расхождение Кульбака-Лейблера в качестве меры расстояния между этими распределениями. Затем вы можете использовать что-то вроде k-ближайший сосед для классификации.

Для двух плотностей вероятностей p и q KL (p, q) = 0, только если p и q совпадают. Однако KL не является симметричным - поэтому, чтобы иметь правильную меру расстояния, вы можете использовать

distance (p1, p2) = KL (p1, p2) + KL (p1, p2)

Для гауссианов, KL (p1, p2) = {(μ1 - μ2) ^ 2 + σ1 ^ 2 - σ2 ^ 2} / (2.σ2 ^ 2) + ln (σ2 / σ1). (Я украл это из здесь , где вы также можете найти отклонение :)

Короче говоря:

Учитывая обучающий набор D (среднее, стандартное, класс) кортежей и новый p = (mean, std), найдите q в D, для которого расстояние (d, p) минимально, и верните этот класс.

Мне кажется, что подход SVM с несколькими ядрами лучше, поскольку способ классификации не такой уж и произвольный.

3
ответ дан 16 December 2019 в 21:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: