2010-04-02 24 views
6

Je suis nouveau dans les SVM et j'essaie d'utiliser l'interface Python pour libsvm pour classer un échantillon contenant une moyenne et stddev. Cependant, je reçois des résultats absurdes.Calcul de la correspondance la plus proche à la paire moyenne/Stddev avec LibSVM

Cette tâche est-elle inappropriée pour les SVM ou y a-t-il une erreur dans mon utilisation de libsvm? Voici le script Python simple que j'utilise pour tester:

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

Le domaine semble assez simple. Je m'attendais à ce que, s'il est entraîné à connaître une moyenne de 2,5 signifie label 1, alors quand il voit une moyenne de 2.4, il devrait retourner l'étiquette 1 comme classification la plus probable. Cependant, chaque noyau a une précision de 0%. Pourquoi est-ce? Un couple de notes secondaires, est-il un moyen de cacher toutes les sorties de formation verbeux déversés par libsvm dans le terminal? J'ai recherché les docs et le code de libsvm, mais je ne trouve aucun moyen de désactiver cela.

En outre, j'avais voulu utiliser des chaînes simples comme clés dans mon jeu de données épars (par exemple {'mean': 2.5, 'stddev': 3.5}). Malheureusement, libsvm ne supporte que les entiers. J'ai essayé d'utiliser la représentation en entier long de la chaîne (par exemple 'mean' == 1109110110971110), mais libsvm semble les tronquer en entiers normaux de 32 bits. La seule solution de contournement que je vois est de conserver un fichier "clé" distinct qui mappe chaque chaîne à un entier ("mean" = 0, "stddev" = 1). Mais évidemment, ça va être pénible car je vais devoir maintenir et maintenir un second fichier avec le classificateur sérialisé. Est-ce que quelqu'un voit un moyen plus facile?

+0

Votre code semble fonctionner, si vous supprimez l'estimation de probabilité (c'est-à-dire, supprimez "probabilité = 1", changez la valeur de predict_probability pour la prédire, et supprimez pred_probability). – dmcer

+0

@dmcer, brillant. Inversement, il semble que je puisse conserver les estimations de probabilité tant que j'ai au moins deux échantillons pour chaque étiquette. Étrange, cela ne fonctionnerait pas pour un seul échantillon par étiquette. Si vous postez votre commentaire comme réponse, je le marquerai comme la réponse acceptée. – Cerin

Répondre

5

Le problème semble provenir de la combinaison de la prédiction multiclasse avec des estimations de probabilité.

Si vous configurez votre code pour ne pas faire d'estimations de probabilité, cela fonctionne en réalité, par ex.:

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

Avec ce changement, je reçois:

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

Prévision des estimations de probabilité fonctionne, si vous doublez les données dans la formation prévue (c.-à-comprennent chaque point de données deux fois) . Cependant, je n'ai pas pu trouver de toute façon de paramétrer le modèle de telle sorte que la prédiction multiclasse avec probabilités fonctionnerait avec seulement les quatre points d'entraînement d'origine.

3

Si vous êtes intéressé par une méthode différente, procédez comme suit. Cette voie est théoriquement plus saine, mais pas aussi simple. En mentionnant mean et std, il semble que vous fassiez référence à des données supposées être distribuées d'une manière ou d'une autre. Par exemple, les données que vous observez sont gaussiennes distribuées. Vous pouvez ensuite utiliser le Symmetrised Kullback-Leibler_divergence comme mesure de distance entre ces distributions. Vous pouvez ensuite utiliser quelque chose comme k-nearest neighbour pour classer.

Pour deux densités de probabilité p et q, vous avez KL (p, q) = 0 seulement si p et q sont identiques. Cependant, KL est pas symétrique - donc afin d'avoir une mesure de distance appropriée, vous pouvez utiliser

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

Pour gaussiennes , KL (p1, p2) = {(μ1 - μ2)^2 + σ1^2 - σ2^2}/(2.σ2^2) + ln (σ2/σ1). (J'ai gagné que de here, où vous pouvez également trouver un écart :)

Longue histoire courte:

Étant donné un ensemble de formation D (moyenne, std, classe) tuples et une nouvelle p = (moyenne, std), trouve que q dans D pour quelle distance (d, p) est minimale et retourne cette classe.

Pour moi, cela se sent mieux que l'approche SVM avec plusieurs noyaux, car la manière de classer n'est pas si arbitraire.

+0

Merci. Je pensais qu'il y avait probablement quelque chose de mieux qu'un SVM pour les distributions normales/gaussiennes. Cependant, j'ai également l'intention d'inclure ces caractéristiques de guassian avec d'autres caractéristiques arbitraires, donc k-nn utilisant une mesure de distance spécialisée ne serait pas approprié. – Cerin

+0

Il existe des moyens d'apprendre de telles mesures de distance à partir des étiquettes de classe. Peut-être que vous voulez vérifier le travail de Sam Roweis sur l'analyse des composantes du quartier. – bayer