2013-08-06 13 views
7

Próbuję nauczyć mojego algorytmu SVM przy użyciu danych kliknięć i konwersji przez osoby, które widzą banery. Główny problem polega na tym, że kliknięcia stanowią około 0,2% wszystkich danych, więc jest to duża dysproporcja. Kiedy używam prostej maszyny SVM w fazie testowania, zawsze przewiduję tylko klasę "widok", a nigdy "kliknięcie" lub "konwersję". Średnio daje to 99,8% poprawnych odpowiedzi (z powodu dysproporcji), ale daje 0% prawych prognoz, jeśli zaznaczysz "kliknięcie" lub "konwersję". W jaki sposób można dostroić algorytm SVM (lub wybrać inny), aby uwzględnić dysproporcję?Jak powinienem uczyć algorytmu uczenia maszynowego przy użyciu danych o dużej dysproporcji klas? (SVM)

+0

wyczynia-próbkowanie Opcjonalnie klasa mniejszościowych? –

+0

Czy możesz powiedzieć więcej o tym, co masz na myśli mówiąc o pobieraniu próbek? – rvnikita

+0

możliwy duplikat [regresji logistycznej sklearn z klasami niezrównoważonymi] (http://stackoverflow.com/questions/14863125/sklearn-logistic-regression-with-balanced-classes) –

Odpowiedz

24

Najbardziej podstawowym podejściem jest użycie tak zwanego "schematu ważenia klasy" - w klasycznym formularzu SVM istnieje parametr C używany do kontrolowania liczby błędów klasyfikacji. Można go zmienić na parametry C1 i C2 dla klas odpowiednio 1 i 2. Najczęstszym wyborem C1 i C2 dla danego C jest umieszczenie

C1 = C/n1 
C2 = C/n2 

gdzie n1 i n2 są rozmiary klasy 1 i 2 odpowiednio. Więc "karzesz" SVM za pomijanie klasy mniejszej, o wiele trudniejszej, niż za typową dla missclassification.

Wiele istniejących bibliotek (takich jak libSVM) obsługuje ten mechanizm z parametrami klasy class_weight.

Przykład użyciu Python i sklearn

print __doc__ 

import numpy as np 
import pylab as pl 
from sklearn import svm 

# we create 40 separable points 
rng = np.random.RandomState(0) 
n_samples_1 = 1000 
n_samples_2 = 100 
X = np.r_[1.5 * rng.randn(n_samples_1, 2), 
      0.5 * rng.randn(n_samples_2, 2) + [2, 2]] 
y = [0] * (n_samples_1) + [1] * (n_samples_2) 

# fit the model and get the separating hyperplane 
clf = svm.SVC(kernel='linear', C=1.0) 
clf.fit(X, y) 

w = clf.coef_[0] 
a = -w[0]/w[1] 
xx = np.linspace(-5, 5) 
yy = a * xx - clf.intercept_[0]/w[1] 


# get the separating hyperplane using weighted classes 
wclf = svm.SVC(kernel='linear', class_weight={1: 10}) 
wclf.fit(X, y) 

ww = wclf.coef_[0] 
wa = -ww[0]/ww[1] 
wyy = wa * xx - wclf.intercept_[0]/ww[1] 

# plot separating hyperplanes and samples 
h0 = pl.plot(xx, yy, 'k-', label='no weights') 
h1 = pl.plot(xx, wyy, 'k--', label='with weights') 
pl.scatter(X[:, 0], X[:, 1], c=y, cmap=pl.cm.Paired) 
pl.legend() 

pl.axis('tight') 
pl.show() 

W szczególności, w sklearn można po prostu włączyć automatycznego ważenia poprzez ustawienie class_weight='auto'.

Visualization of above code from sklearn documentation

+0

Dziękuję bardzo, właśnie tego szukam. Szkoda, że ​​nie mam 15 punktów, aby zagłosować na tę odpowiedź :) – rvnikita

+0

Jestem prawie pewien, że nadal możesz sprawdzić opcję "zaakceptuj odpowiedź" :) – lejlot

1

Opisano szereg technik. Jeden prosty (ale bardzo zła metoda SVM) jest po prostu replikacji klasę (-y) mniejszościowy aż masz balans:

http://www.ele.uri.edu/faculty/he/PDFfiles/ImbalancedLearning.pdf

+0

Tylko dla kompletności - replikacja klasy mniejszości powinna ** nigdy ** być używana w SVM. Jest to równoważne użyciu ciężarów klasowych, podczas gdy w tym samym czasie jest całkowicie nieefektywne pod względem czasu szkolenia (i testowania). – lejlot

+0

Edytowałem moją oryginalną odpowiedź, aby odzwierciedlić komentarz Lejlot. – denson

Powiązane problemy