Pregunta

Soy nuevo en SVM, y yo estoy tratando de utilizar la interfaz de Python para libsvm para clasificar una muestra que contiene una media y STDDEV. Sin embargo, estoy recibiendo resultados sin sentido.

¿Es esta tarea inadecuada para SVM o hay un error en mi uso de libsvm? A continuación es el simple script en Python que estoy usando para la prueba:

#!/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))

El dominio parece bastante simple. Yo esperaría que si está capacitado para conocer una media de 2,5 medios etiqueta 1, a continuación, cuando se ve una media de 2,4, debe devolver etiqueta 1 como el más probable clasificación. Sin embargo, cada núcleo tiene una precisión de 0%. ¿Por qué es esto?

Un par de notas al margen, hay una manera de ocultar toda la salida de entrenamiento detallado del abandono de libsvm en el terminal? He buscado documentos y código de libSVM, pero no puedo encontrar ninguna manera de desactivar esta opción.

Además, había querido utilizar cadenas simples como las llaves en el conjunto de datos escasa (por ejemplo, { 'media': 2,5 'STDDEV': 3,5}). Por desgracia, libsvm sólo admite números enteros. He intentado utilizar la representación entero largo de la cadena (por ejemplo, 'media' == 1109110110971110), pero parece que libsvm truncan a enteros normales estos 32 bits. La única solución que veo es mantener un archivo separado "llave" que mapea cada cadena en un entero ( 'media' = 0, 'STDDEV' = 1). Pero, obviamente, que va a ser difícil ya que voy a tener que mantener y conservar un segundo archivo, junto con el clasificador serializado. ¿Alguien ve una manera más fácil?

¿Fue útil?

Solución

El problema parece ser que viene de la combinación de predicción multiclase con las estimaciones de probabilidad.

Si se configura el código no para hacer estimaciones de probabilidad, en realidad funciona , por ejemplo:.

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

Con este cambio, me sale:

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

Predicción con las estimaciones de probabilidad funciona, si se duplica seguridad de los datos en el conjunto de entrenamiento (es decir, incluyen cada punto de datos dos veces). Sin embargo, no pude encontrar modos para parametrizar el modelo para que la predicción multiclase con probabilidades trabajaría con sólo los cuatro puntos de entrenamiento originales.

Otros consejos

Si está interesado en una forma diferente de hacer esto, usted podría hacer lo siguiente. De esta manera es teóricamente más sonido, sin embargo no es tan sencillo.

Al mencionar media y std, parece como si se refiere a los datos que se asume para ser distribuidos de alguna manera. Por ejemplo, los datos que se distribuye observadores de Gauss. A continuación, puede utilizar la Symmetrised Kullback-Leibler_divergence como una medida de la distancia entre las distribuciones . A continuación, puede usar algo como k-vecino más cercano de clasificar.

Para densidades de dos de probabilidad p y q, que tiene KL (p, q) = 0 sólo si p y q son los mismos. Sin embargo, no es simétrica KL - por lo que con el fin de tener una medida de la distancia adecuada, puede utilizar

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

Para gaussianas, KL (p1, p2) = {(μ1 - μ2) ^ 2 + σ1 ^ 2 - σ2 ^ 2} / (2.σ2 ^ 2) + ln (σ2 / σ1). (Robé que desde aquí donde podrá ver también una desviación: )

Para acortar una larga historia:

Dado un conjunto de entrenamiento D de tuplas (media, std, clase) y un nuevo p = (media, STD) de par, encontrar que q en D para el que la distancia (d, p) es mínimo y volver esa clase.

Para mí que se siente mejor como el enfoque SVM con varios núcleos, ya que la forma de clasificar no es tan arbitraria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top