Schritt für Schritt zur Theorie, Implementierung in Python und Analyse mit scikit-learn über den Algorithmus, der zuvor in "Klassifikation des maschinellen Lernens" verwendet wurde. Ich werde mit lernen. Ich schreibe es zum persönlichen Lernen, daher möchte ich, dass Sie alle Fehler übersehen.
Letztes Mal schrieb ich über die Grundlagen der Support-Vektor-Maschine. Letztes Mal haben wir uns mit SVM befasst, das als harte Marge bezeichnet wird und positive und negative Fälle richtig trennen kann, aber diesmal
Ich möchte über erwähnen.
Stellen Sie sich ein Beispiel vor, in dem die roten und blauen Kreise im Gegensatz zur vorherigen Zeit nicht subtil voneinander getrennt werden können (siehe Abbildung unten).
Der SVM-Ausdruck mit hartem Rand besteht aus einer Reihe von Parametern
Führen Sie zur Entspannung die Slack-Variable $ \ xi $ und den Parameter $ C $ ein. Die Slack-Variable ist eine Variable darüber, wie viel Fehler zwischen dem Unterstützungsvektor und der Grenzlinie zulässig ist, und $ C (> 0) $ repräsentiert die Strenge der Einschränkungsbedingung. Wenn diese eingeführt werden, ändert sich das oben beschriebene zu lösende Problem wie folgt.
\frac{1}{2}|w|^2+C\sum_{i=1}^{N}\xi_i \\
t_n(\boldsymbol{w}^Tx_n+w_0) \geq 1-\xi_n \\
\xi_n \geq 0
In Bezug auf die Beziehung zwischen $ C $ und $ \ xi $ kann $ C $, wenn sie groß ist, nur minimiert werden, wenn $ \ xi $ klein ist, und wenn $ C $ klein ist, kann sie minimiert werden, selbst wenn $ \ xi $ bis zu einem gewissen Grad groß ist. Es bedeutet das. Wenn $ C $ unendlich ist, entspricht dies einer SVM mit hartem Rand, da $ \ xi $ nur Null tolerieren kann (= keine Daten innerhalb des Randes zulassen).
Im Gegensatz zur harten Marge wurde die Einschränkung auf zwei erhöht, sodass der Lagrange-Multiplikator auch auf $ \ lambda $ und $ \ mu $ gesetzt ist.
L(w,w_0,\lambda, \mu)=\frac{1}{2}|w|^2+C\sum_{i=1}^n\xi_i-\sum_{i=1}^{N}\lambda_i \{ t_i(\boldsymbol{w}^Tx_i+w_0)+\xi_i-1\}-\sum_{i=1}^n\mu_i\xi_i
Wenn dies für $ w $, $ w_0 $ und $ \ xi $ teilweise differenziert und auf Null gesetzt ist,
w=\sum_{i=1}^n\lambda_it_ix_i \\
\sum_{i=1}^n\lambda_it_i=0 \\
\lambda_i=C-\mu_i
Kann erhalten werden, und wenn der Lagrange-Funktion zugewiesen,
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_mx_n^Tx_m
Und das ist genau die gleiche Formel wie für den harten Rand. Die Einschränkung ist jedoch
\sum_{i=1}^n\lambda_it_n=0 \\
0 \leq \lambda_i \leq C
Es wird sein. Wie beim harten Rand ist es möglich, die Parameter mit SMO zu finden. (Diesmal weggelassen)
Betrachten Sie das folgende Beispiel, das durch eine gerade Linie untrennbar zu sein scheint.
Wenn es eine solche Form hat, verschieben Sie den Punkt in einen höherdimensionalen Raum und trennen Sie dann die Ebenen, z. B. 2D → 3D. Die Methode zum Konvertieren in eine höhere Ordnung wird als ** Kernel-Methode ** bezeichnet, und die Funktion zum Konvertieren wird als ** Kernelfunktion ** bezeichnet.
Eine Datenzeichenfolge, die $ \ boldsymbol {x} = (x_0, x_1, \ cdots, x_ {n-1}) $ projiziert, ist $ \ boldsymbol {\ phi} = \ {\ phi_0 (\ boldsymbol {x) }), \ phi_1 (\ boldsymbol {x}), \ cdots, \ phi_ {m-1} (\ boldsymbol {x}) \} $. Dieses $ \ phi (x) $ heißt ** Basisfunktion **. Da die vorherige SVM die lineare Trennung verarbeiten konnte, entsprach die Basisfunktion
Durch Anwenden der Basisfunktion ändert sich der Teil $ x_n ^ Tx_m $ der Lagrange-Funktion in $ \ phi (x) _n ^ T \ phi (x) _m $.
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_m\phi(x)_n^T\phi(x)_m
Dieses $ \ phi (x) _n ^ T \ phi (x) _m $ ist eine interne Produktberechnung, und wenn es viele Datenpunkte gibt, wird der Rechenaufwand enorm sein, daher werden wir ein wenig darüber nachdenken.
Tatsächlich kann $ \ phi (x) _n ^ T \ phi (x) _m $ durch $ k (x_n, k_m) $ ersetzt werden. $ k (x_n, k_m) $ heißt ** Kernelfunktion **. Wenn Sie es auf diese Weise ersetzen, können Sie die mühsame interne Produktberechnung weglassen. Dies nennt man ** Kernel-Trick **. Weitere Informationen finden Sie unter "Kernel Trick".
Insbesondere wird die Kernelfunktion, die die oben erwähnte Gaußsche Basisfunktion verwendet, als ** RBF-Kernel (Radialbasisfunktionskernel) ** bezeichnet.
Endlich die Lagrange-Funktion
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_mk(x_n,x_m) \\
\text{subject.to }\sum_{i=1}^n\lambda_it_n=0,0 \leq \lambda_i \leq C
Es wird sein. Tatsächlich ist diese Formel gelöst, und nachdem Sie $ \ lambda $ gefunden haben, finden Sie $ \ boldsymbol {w} $ und $ w_0 $.
Letztes Mal haben wir nach einfachem sklearn.svm.LinearSVC klassifiziert, aber allgemeiner sklearn. Versuchen Sie es mit .svm.SVC.
Die Erklärung der API sieht wie folgt aus.
class sklearn.svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='scale', coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape='ovr', break_ties=False, random_state=None)
Wenn Sie den Inhalt bisher verstanden haben, können Sie diese Erklärung nach und nach verstehen. Der "Kernel" -Parameter ist der Parameter, der die Basisfunktion bestimmt, die "linear" für linear und "rbf" für Gaußschen Kernel ist. Die wichtigsten hier sind "C" und "Gamma".
C
ist ein Parameter, der die Stärke der Einschränkungsbedingung bestimmt. Je größer der Parameter ist, desto strenger ist die Einschränkung. gamma
ist ein Parameter, der die Ausbreitung der Gaußschen Basisfunktion bestimmt, und es ist eine inverse Zahl. Je kleiner sie ist, desto glatter wird sie.
Verwenden Sie die zuerst angezeigten Daten als zu klassifizierende Daten. Tatsächlich verwenden diese Daten eine API namens sklearn.datasets.make_moons. Sie können die Anzahl der Samples und die Rauschstärke angeben. Die Entscheidungsgrenze ist ebenfalls dargestellt. Da die Entscheidungsgrenze nicht linear ist, wird sie als Konturlinie gezeichnet. Insbesondere verwenden wir eine Funktion namens contourf of matplotlib.
import numpy as np
import pandas as pd
from sklearn import svm
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
%matplotlib inline
X, y = make_moons(n_samples=200,
shuffle = True,
noise = 0.1,
random_state = 2020,)
a0, b0 = X[y==0,0], X[y==0,1]
a1, b1 = X[y==1,0], X[y==1,1]
model = svm.SVC(C=1.0, kernel='rbf', gamma=1)
model.fit(X, y)
x1_min,x1_max = X[:,0].min() - 0.1,X[:,0].max() + 0.1
x2_min,x2_max = X[:,1].min() - 0.1,X[:,1].max() + 0.1
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,0.02),
np.arange(x2_min,x2_max,0.02))
Z = model.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.figure(figsize=(8, 7))
plt.contourf(xx1,xx2,Z,alpha = 0.4)
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
plt.scatter(a0, b0, marker='o', s=25, label="y = 0")
plt.scatter(a1, b1, marker='o', s=25, label="y = 1")
plt.legend()
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
Es scheint, dass sie getrennt werden können. Mit der API können Sie auch den Unterstützungsvektor abrufen, dieser kann jedoch mit einer kleinen Datenmenge im Vergleich zur tatsächlichen Datenmenge angenähert werden, was zur Speicherersparnis und Beschleunigung der Berechnung beiträgt.
Oben habe ich "C" und "Gamma" entsprechend entschieden, aber was ist, wenn ich dies ändere? Lassen Sie es uns tatsächlich zeichnen.
list_C = [0.1, 1, 20]
list_gamma = [0.05, 0.5, 20]
x1_min,x1_max = X[:,0].min() - 0.1,X[:,0].max() + 0.1
x2_min,x2_max = X[:,1].min() - 0.1,X[:,1].max() + 0.1
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,0.02),
np.arange(x2_min,x2_max,0.02))
plt.figure(figsize=(11, 11))
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
plt.xlabel("x1")
plt.ylabel("x2")
for i in range(len(list_C)):
for j in range(len(list_gamma)):
model = svm.SVC(C=list_C[i], kernel='rbf', gamma=list_gamma[j])
model.fit(X, y)
Z = model.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
ax = plt.subplot(len(list_C), len(list_gamma), i*len(list_C)+j+1)
ax.set_title("C={}, gamma={}".format(list_C[i], list_gamma[j]))
ax.contourf(xx1,xx2,Z,alpha = 0.4)
ax.scatter(a0, b0, marker='o', s=25, label="y = 0")
ax.scatter(a1, b1, marker='o', s=25, label="y = 1")
plt.show()
Das Ergebnis ist wie folgt.
Wie oben erläutert, ist die Kurve umso komplexer, je größer das "C" ist, desto besser ist die Trennung, und je größer das "Gamma" ist. Unten rechts sieht es jedoch so aus, als wäre es ein Überlernen, und es scheint, dass eine Parameteroptimierung erforderlich sein wird.
Um die Parameter abzustimmen, ist es erforderlich, die Stichprobe in Trainingsdaten und Verifizierungsdaten zu unterteilen und nach Parametern zu suchen, die einen hohen Grad an Übereinstimmung aufweisen, wenn sie durch die Verifizierungsdaten vorhergesagt werden. Dies wird als "Kreuzvalidierung" bezeichnet, aber ich werde versuchen, es zu einem anderen Zeitpunkt zusammenzufassen.
Die Support-Vektor-Maschine wurde vom harten Rand zum weichen Rand erweitert, um die nichtlineare Trennung zu handhaben. Wenn ich es so betrachte, hatte ich das Gefühl, dass ich selbst ziemlich komplizierte Klassifikationen ablehnen könnte. Es ist verständlich, dass es vor dem neuronalen Netz beliebt war.
Recommended Posts