Wie zeichne ich die Hyperebenen für SVM One-Versus-All?

Nov 26 2020

Ich habe versucht, die Hyperebenen zu zeichnen, als SVM-OVA wie folgt durchgeführt wurde:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
x = np.array([[1,1.1],[1,2],[2,1]])
y = np.array([0,100,250])
classifier = OneVsRestClassifier(SVC(kernel='linear'))

Basierend auf der Antwort auf diese Frage Plot Hyperplane Linear SVM Python habe ich den folgenden Code geschrieben:

fig, ax = plt.subplots()
# create a mesh to plot in
x_min, x_max = x[:, 0].min() - 1, x[:, 0].max() + 1
y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
xx2, yy2 = np.meshgrid(np.arange(x_min, x_max, .2),np.arange(y_min, y_max, .2))
Z = classifier.predict(np.c_[xx2.ravel(), yy2.ravel()])
Z = Z.reshape(xx2.shape)
ax.contourf(xx2, yy2, Z, cmap=plt.cm.winter, alpha=0.3)
ax.scatter(x[:, 0], x[:, 1], c=y, cmap=plt.cm.winter, s=25)

# First line: class1 vs (class2 U class3)
w = classifier.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[0]) / w[1]
ax.plot(xx,yy)

# Second line: class2 vs (class1 U class3)
w = classifier.coef_[1]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[1]) / w[1]
ax.plot(xx,yy)

# Third line: class 3 vs (class2 U class1)
w = classifier.coef_[2]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[2]) / w[1]
ax.plot(xx,yy)

Dies ist jedoch, was ich erhalten habe:

Die Linien sind eindeutig falsch: Tatsächlich scheinen die Winkelkoeffizienten korrekt zu sein, aber nicht die Abschnitte. Insbesondere wäre die orange Linie korrekt, wenn sie um 0,5 nach unten übersetzt würde, die grüne, wenn sie um 0,5 nach links übersetzt würde, und die blaue Linie, wenn sie um 1,5 nach oben übersetzt würde.

Bin ich falsch, die Linien zu zeichnen, oder funktioniert der Klassifikator aufgrund der wenigen Trainingspunkte nicht richtig?

Antworten

5 meTchaikovsky Dec 01 2020 at 12:38

Das Problem ist, dass der CParameter von SVCzu klein ist (standardmäßig 1.0). Nach diesem Beitrag ,

Umgekehrt führt ein sehr kleiner Wert von C dazu, dass der Optimierer nach einer Hyperebene mit größerem Rand sucht, selbst wenn diese Hyperebene mehr Punkte falsch klassifiziert.

Daher besteht die Lösung darin, beispielsweise eine viel größere Czu verwenden1e5

import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier


x = np.array([[1,1.1],[1,2],[2,1]])
y = np.array([0,100,250])
classifier = OneVsRestClassifier(SVC(C=1e5,kernel='linear'))
classifier.fit(x,y)

fig, ax = plt.subplots()
# create a mesh to plot in
x_min, x_max = x[:, 0].min() - 1, x[:, 0].max() + 1
y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
xx2, yy2 = np.meshgrid(np.arange(x_min, x_max, .2),np.arange(y_min, y_max, .2))
Z = classifier.predict(np.c_[xx2.ravel(), yy2.ravel()])
Z = Z.reshape(xx2.shape)
ax.contourf(xx2, yy2, Z, cmap=plt.cm.winter, alpha=0.3)
ax.scatter(x[:, 0], x[:, 1], c=y, cmap=plt.cm.winter, s=25)

def reconstruct(w,b):

    k = - w[0] / w[1]
    b = - b[0] / w[1]

    if k >= 0:
        x0 = max((y_min-b)/k,x_min)
        x1 = min((y_max-b)/k,x_max)
    else:
        x0 = max((y_max-b)/k,x_min)
        x1 = min((y_min-b)/k,x_max)
    if np.abs(x0) == np.inf: x0 = x_min
    if np.abs(x1) == np.inf: x1 = x_max
    
    xx = np.linspace(x0,x1)
    yy = k*xx+b

    return xx,yy

xx,yy = reconstruct(classifier.coef_[0],classifier.intercept_[0])
ax.plot(xx,yy,'r')
xx,yy = reconstruct(classifier.coef_[1],classifier.intercept_[1])
ax.plot(xx,yy,'g')
xx,yy = reconstruct(classifier.coef_[2],classifier.intercept_[2])
ax.plot(xx,yy,'b')

Dieses Mal Csieht das Ergebnis besser aus , da ein viel größeres übernommen wird