1

Ich habe 9164 Punkte, wobei 4303 als die Klasse, die ich vorhersagen möchte, und 4861 als nicht diese Klasse bezeichnet werden. Sie sind keine doppelten Punkte.sklearn SVM funktioniert furchtbar schlecht

Nach How to split into train, test and evaluation sets in sklearn?, und da meine dataset ist ein Tupel von 3 Elemente (id, Vektor, Label), das tue ich:

df = pd.DataFrame(dataset) 
train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))]) 

train_labels = construct_labels(train) 
train_data = construct_data(train) 

test_labels = construct_labels(test) 
test_data = construct_data(test) 

def predict_labels(test_data, classifier): 
    labels = [] 
    for test_d in test_data: 
     labels.append(classifier.predict([test_d])) 
    return np.array(labels) 

def construct_labels(df): 
    labels = [] 
    for index, row in df.iterrows(): 
     if row[2] == 'Trump': 
      labels.append('Atomium') 
     else: 
      labels.append('Not Trump') 
    return np.array(labels) 

def construct_data(df): 
    first_row = df.iloc[0] 
    data = np.array([first_row[1]]) 
    for index, row in df.iterrows(): 
     if first_row[0] != row[0]: 
      data = np.concatenate((data, np.array([row[1]])), axis=0) 
    return data 

und dann:

>>> classifier = SVC(verbose=True) 
>>> classifier.fit(train_data, train_labels) 
[LibSVM].......*..* 
optimization finished, #iter = 9565 
obj = -2718.376533, rho = 0.132062 
nSV = 5497, nBSV = 2550 
Total nSV = 5497 
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0, 
    decision_function_shape=None, degree=3, gamma='auto', kernel='rbf', 
    max_iter=-1, probability=False, random_state=None, shrinking=True, 
    tol=0.001, verbose=True) 
>>> predicted_labels = predict_labels(test_data, classifier) 
>>> for p, t in zip(predicted_labels, test_labels): 
...  if p == t: 
...    correct = correct + 1 

und ich richtig bekommen nur 943 Etiketten aus 1833 (= len (test_labels)) -> (943 * 100/1843 = 51,4%)


ich bin suspe Wenn ich hier etwas Großes verpasse, sollte ich vielleicht einen parameter zum Klassifikator setzen, um raffiniertere Arbeit oder etwas zu tun?

Hinweis: Zum ersten Mal SVMs hier verwendet wird, so alles, was Sie vielleicht für selbstverständlich bekommen, könnte ich mir vorstellen, nicht einmal haben ...


Versuch:

ich ahed ging und verringert die Anzahl der negative Beispiele zu 4303 (gleiche Anzahl wie positive Beispiele). Diese etwas verbesserte Genauigkeit.


Bearbeiten nach der Antwort:

>>> print(clf.best_estimator_) 
SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0, 
    decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf', 
    max_iter=-1, probability=False, random_state=None, shrinking=True, 
    tol=0.001, verbose=False) 
>>> classifier = SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0, 
... decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf', 
... max_iter=-1, probability=False, random_state=None, shrinking=True, 
... tol=0.001, verbose=False) 
>>> classifier.fit(train_data, train_labels) 
SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0, 
    decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf', 
    max_iter=-1, probability=False, random_state=None, shrinking=True, 
    tol=0.001, verbose=False) 

Auch habe ich versucht clf.fit(train_data, train_labels), die gleich ausgeführt.


Bearbeiten mit Daten (die Daten sind nicht zufällig):

>>> train_data[0] 
array([ 20.21062112, 27.924016 , 137.13815308, 130.97432804, 
     ... # there are 256 coordinates in total 
     67.76352596, 56.67798138, 104.89566517, 10.02616417]) 
>>> train_labels[0] 
'Not Trump' 
>>> train_labels[1] 
'Trump' 
+0

SVMs benötigen Parameter-Tuning, was sehr wichtig ist (besonders nichtlineare Kernel). Du scheinst diese nicht zu stimmen. Es ist auch sehr wichtig, Ihre Daten zu standardisieren (Mittelwert und Varianz). Verwenden Sie scikit-learns * GridSearchCV *, um diese automatisch mit der Kreuzvalidierung abzustimmen. – sascha

+0

@sascha könnten Sie bitte ein Beispiel oder etwas mehr bieten? Ich bin wirklich ein Neuling hier! Und was du sagst, klingt wirklich richtig! – gsamaras

+0

Lesen Sie einfach scikit-learns [Benutzer-Guide] (http://scikit-learn.org/stable/modules/svm.html). Dies sind sehr elementare Schritte und ich bin verwirrt, warum Leute solch ein theoretisch komplexes Konzept wie SVMs verwenden, ohne auch nur die grundlegenden Nutzungsregeln zu lesen. [Heres ein GridSearch-Beispiel] (http://scikit-learn.org/stable/auto_examples/svm/plot_rbf_parameters.html), das auch zeigt, wie wichtig Parameter-Tuning ist -> Genauigkeiten zwischen ~ [0.2, 0.95] – sascha

Antwort

5

meisten Schätzer in Scikit-Learn wie SVC sind mit einer Anzahl von Eingabeparametern eingeleitet, die auch als Hyperparameter bekannt. Abhängig von Ihren Daten müssen Sie herausfinden, was während der Initialisierung als Eingaben für den Schätzer übergeben werden soll. Wenn Sie sich die SVC-Dokumentation in scikit-learn ansehen, sehen Sie, dass sie mit mehreren verschiedenen Eingabeparametern initialisiert werden kann.

Der Einfachheit halber betrachten wir Kernel, der 'rbf' oder 'linear' sein kann (unter ein paar anderen Möglichkeiten); und C, der ein Penalty-Parameter ist, und Sie wollen die Werte 0.01, 0.1, 1, 10, 100 für C ausprobieren. Das wird zu 10 verschiedenen möglichen Modellen führen, die erstellt und ausgewertet werden können.

Eine einfache Lösung besteht darin, zwei geschachtelte for-Schleifen für den Kernel und die andere für C zu schreiben und die 10 möglichen Modelle zu erstellen und zu sehen, welches Modell das beste ist. Wenn Sie jedoch mehrere Hyperparameter einstellen müssen, müssen Sie mehrere verschachtelte For-Loops schreiben, was mühsam sein kann.

Glücklicherweise hat scikit learn eine bessere Möglichkeit, verschiedene Modelle auf der Grundlage verschiedener Wertekombinationen für Ihr Hypermodell zu erstellen und das beste auszuwählen. Dafür verwenden Sie GridSearchCV. GridSearchCV wird mit zwei Dingen initialisiert: einer Instanz eines Schätzers und einem Lexikon mit Hyperparametern und den gewünschten zu prüfenden Werten. Es wird dann ausgeführt und erstellt alle möglichen Modelle angesichts der Auswahl von Hyperparametern und findet die beste, daher müssen Sie keine verschachtelten for-Schleifen schreiben.Hier ein Beispiel:

from sklearn.grid_search import GridSearchCV 
print("Fitting the classifier to the training set") 
param_grid = {'C': [0.01, 0.1, 1, 10, 100], 'kernel': ['rbf', 'linear']} 
clf = GridSearchCV(SVC(class_weight='balanced'), param_grid) 
clf = clf.fit(train_data, train_labels) 
print("Best estimator found by grid search:") 
print(clf.best_estimator_) 

Sie müssen etwas ähnliches zu diesem Beispiel verwenden und mit verschiedenen Hyperparametern spielen. Wenn Sie eine gute Auswahl an Werten für Ihre Hyperparameter haben, besteht eine sehr gute Chance, dass Sie auf diese Weise ein viel besseres Modell finden.

Es ist jedoch möglich, dass GridSearchCV sehr lange braucht, um alle diese Modelle zu erstellen, um den besten zu finden. Ein praktischerer Ansatz besteht darin, stattdessen RandomizedSearchCV zu verwenden, das zufällig eine Teilmenge aller möglichen Modelle (unter Verwendung der Hyperparameter) erstellt. Es sollte viel schneller laufen, wenn Sie viele Hyperparameter haben, und das beste Modell ist normalerweise ziemlich gut.

+0

Die Antwort fehlt einige Erklärungen, aber es sollte dem OP helfen. Nur einige Bemerkungen: GridSearchCV versucht nicht alle möglichen Modelle, sondern das kartesische Produkt (geordnete Kombinationen) der Parameter-Kandidaten definiert hier durch Shahins. Auch: C und Gamma sind die wichtigsten Parameter bei der Verwendung von SVM + rbf-Kernel, also sind diese hier abgestimmt (es gibt mehr). Noch eine Bemerkung: Das Konzept der Kreuzvalidierung ist unabhängig von SVMs. Dies ist etwas, über das auch gelesen werden sollte (es gibt auch viele Parameter/Konzepte). – sascha

+0

shashins, was passt da? Meintest du nicht 'clf.fit (train_data, train_labels)'? Ich habe nur die Antwort angewendet und eine Genauigkeit von 49,8% erreicht, mit meinem Versuch, das ist überhaupt nicht besser ...:/Irgendein anderer Gedanke? Ich denke auch, dass ich noch etwas Dummes machen könnte, überprüfe meine aktualisierte Frage bitte! :) – gsamaras

+0

Ich habe mehr Erklärungen in meiner Antwort hinzugefügt. Ich hoffe, es hilft. – shahins

1

Nach den Kommentaren von sascha und die Antwort von shahins, tat ich dies schließlich:

df = pd.DataFrame(dataset) 
train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))]) 

train_labels = construct_labels(train) 
train_data = construct_data(train) 

test_labels = construct_labels(test) 
test_data = construct_data(test) 

from sklearn.preprocessing import StandardScaler 
scaler = StandardScaler() 
train_data = scaler.fit_transform(train_data) 

from sklearn.svm import SVC 
# Classifier found with shahins' answer 
classifier = SVC(C=10, cache_size=200, class_weight='balanced', coef0=0.0, 
    decision_function_shape=None, degree=3, gamma='auto', kernel='rbf', 
    max_iter=-1, probability=False, random_state=None, shrinking=True, 
    tol=0.001, verbose=False) 
classifier = classifier.fit(train_data, train_labels) 

test_data = scaler.fit_transform(test_data) 
predicted_labels = predict_labels(test_data, classifier) 

und bekam:

>>> correct_labels = count_correct_labels(predicted_labels, test_labels) 
>>> print_stats(correct_labels, len(test_labels)) 
Correct labels = 1624 
Accuracy = 88.5979268958 

mit diesen Methoden:

def count_correct_labels(predicted_labels, test_labels): 
    correct = 0 
    for p, t in zip(predicted_labels, test_labels): 
     if p[0] == t: 
      correct = correct + 1 
    return correct 

def print_stats(correct_labels, len_test_labels): 
    print "Correct labels = " + str(correct_labels) 
    print "Accuracy = " + str((correct_labels * 100/float(len_test_labels))) 

Ich war in der Lage, mit mehr Hyper-Parameter-Tuning mehr zu optimieren!

Hilfreiche Link: RBF SVM parameters


Hinweis: Wenn ich die test_data nicht verwandeln, Genauigkeit beträgt 52,7%.

+0

Gute Arbeit. Sieht so aus, als ob du es funktioniert hast. – shahins

+0

Danke @shahins, deine Hilfe war wertvoll! Ich habe auch die [Verwirrungsmatrix] geplottet (http://stackoverflow.com/questions/19233771/sklearn-plot-confusion-matrix-with-labels). Hoffentlich hilft meine Antwort auch dem zukünftigen User trotz seines * 0 * Ergebnisses ein wenig! :) – gsamaras

Verwandte Themen