Maszyna wektorów wsparcia (SVM)

Wprowadzenie do SVM

Maszyny wektorów nośnych (SVM) to potężne, ale elastyczne nadzorowane algorytmy uczenia maszynowego, które są używane zarówno do klasyfikacji, jak i regresji. Ale ogólnie są używane w problemach klasyfikacyjnych. W latach 60. po raz pierwszy wprowadzono maszyny SVM, ale później udoskonalono je w 1990 r. Maszyny SVM mają swój unikalny sposób implementacji w porównaniu z innymi algorytmami uczenia maszynowego. Ostatnio są niezwykle popularne ze względu na ich zdolność do obsługi wielu zmiennych ciągłych i kategorialnych.

Działanie SVM

Model SVM jest w zasadzie reprezentacją różnych klas w hiperpłaszczyźnie w przestrzeni wielowymiarowej. Hiperpłaszczyzna zostanie wygenerowana w sposób iteracyjny przez SVM, aby zminimalizować błąd. Celem SVM jest podzielenie zbiorów danych na klasy w celu znalezienia maksymalnej marginalnej hiperpłaszczyzny (MMH).

Poniżej znajdują się ważne pojęcia w SVM -

  • Support Vectors- Punkty danych, które są najbliżej hiperpłaszczyzny, nazywane są wektorami nośnymi. Za pomocą tych punktów danych zostanie zdefiniowana linia oddzielająca.

  • Hyperplane - Jak widać na powyższym diagramie, jest to płaszczyzna decyzyjna lub przestrzeń, która jest podzielona na zbiór obiektów o różnych klasach.

  • Margin- Można to zdefiniować jako lukę między dwiema liniami w szafowych punktach danych różnych klas. Można ją obliczyć jako prostopadłą odległość od linii do wektorów nośnych. Duży margines jest uważany za dobry, a mały za zły.

Głównym celem SVM jest podzielenie zbiorów danych na klasy w celu znalezienia maksymalnej marginalnej hiperpłaszczyzny (MMH) i można to zrobić w dwóch następujących krokach -

  • Po pierwsze, SVM generuje iteracyjnie hiperpłaszczyzny, które w najlepszy sposób segregują klasy.

  • Następnie wybierze hiperpłaszczyznę, która prawidłowo oddziela klasy.

Implementacja SVM w Pythonie

Aby zaimplementować SVM w Pythonie, zaczniemy od importu bibliotek standardowych w następujący sposób -

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns; sns.set()

Następnie tworzymy przykładowy zestaw danych zawierający dane, które można rozdzielić liniowo, ze sklearn.dataset.sample_generator do klasyfikacji przy użyciu SVM -

from sklearn.datasets.samples_generator import make_blobs
X, y = make_blobs(n_samples=100, centers=2, random_state=0, cluster_std=0.50)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer');

Po wygenerowaniu przykładowego zestawu danych zawierającego 100 próbek i 2 klastry uzyskanoby następujące wyniki:

Wiemy, że SVM obsługuje klasyfikację dyskryminacyjną. oddziela klasy od siebie, po prostu znajdując linię w przypadku dwóch wymiarów lub rozmaitość w przypadku wielu wymiarów. Jest zaimplementowany na powyższym zbiorze danych w następujący sposób -

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
plt.plot([0.6], [2.1], 'x', color='black', markeredgewidth=4, markersize=12)
for m, b in [(1, 0.65), (0.5, 1.6), (-0.2, 2.9)]:
   plt.plot(xfit, m * xfit + b, '-k')
plt.xlim(-1, 3.5);

Dane wyjściowe są następujące -

Z powyższego wyniku widać, że istnieją trzy różne separatory, które doskonale rozróżniają powyższe próbki.

Jak wspomniano, głównym celem SVM jest podzielenie zbiorów danych na klasy w celu znalezienia maksymalnej marginalnej hiperpłaszczyzny (MMH), dlatego zamiast rysować linię zerową między klasami, możemy narysować wokół każdej linii margines o pewnej szerokości do najbliższego punktu. Można to zrobić w następujący sposób -

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
   for m, b, d in [(1, 0.65, 0.33), (0.5, 1.6, 0.55), (-0.2, 2.9, 0.2)]:
   yfit = m * xfit + b
   plt.plot(xfit, yfit, '-k')
   plt.fill_between(xfit, yfit - d, yfit + d, edgecolor='none',
         color='#AAAAAA', alpha=0.4)
plt.xlim(-1, 3.5);

Na powyższym obrazie wyjściowym możemy łatwo zaobserwować „marginesy” w klasyfikatorach dyskryminacyjnych. SVM wybierze linię, która maksymalizuje margines.

Następnie użyjemy klasyfikatora wektorów pomocniczych Scikit-Learn, aby wytrenować model SVM na tych danych. Tutaj używamy jądra liniowego do dopasowania SVM w następujący sposób -

from sklearn.svm import SVC # "Support vector classifier"
model = SVC(kernel='linear', C=1E10)
model.fit(X, y)

Dane wyjściowe są następujące -

SVC(C=10000000000.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='linear', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False)

Teraz, dla lepszego zrozumienia, poniżej wykreślimy funkcje decyzyjne dla 2D SVC -

def decision_function(model, ax=None, plot_support=True):
   if ax is None:
      ax = plt.gca()
   xlim = ax.get_xlim()
   ylim = ax.get_ylim()

Aby ocenić model, musimy utworzyć siatkę w następujący sposób -

x = np.linspace(xlim[0], xlim[1], 30)
y = np.linspace(ylim[0], ylim[1], 30)
Y, X = np.meshgrid(y, x)
xy = np.vstack([X.ravel(), Y.ravel()]).T
P = model.decision_function(xy).reshape(X.shape)

Następnie musimy wykreślić granice decyzyjne i marginesy w następujący sposób -

ax.contour(X, Y, P, colors='k',
   levels=[-1, 0, 1], alpha=0.5,
   linestyles=['--', '-', '--'])

Teraz podobnie wykreśl wektory pomocnicze w następujący sposób -

if plot_support:
   ax.scatter(model.support_vectors_[:, 0],
      model.support_vectors_[:, 1],
      s=300, linewidth=1, facecolors='none');
ax.set_xlim(xlim)
ax.set_ylim(ylim)

Teraz użyj tej funkcji, aby dopasować nasze modele w następujący sposób -

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
decision_function(model);

Z powyższego wyniku możemy zauważyć, że klasyfikator SVM dopasowuje się do danych z marginesami, tj. Liniami przerywanymi i wektorami pomocniczymi, czyli kluczowymi elementami tego dopasowania, dotykającymi linii przerywanej. Te punkty wektorów nośnych są przechowywane w atrybucie support_vectors_ klasyfikatora w następujący sposób -

model.support_vectors_

Dane wyjściowe są następujące -

array([[0.5323772 , 3.31338909],
   [2.11114739, 3.57660449],
   [1.46870582, 1.86947425]])

Jądra SVM

W praktyce algorytm SVM jest implementowany z jądrem, które przekształca przestrzeń danych wejściowych do wymaganej postaci. SVM wykorzystuje technikę zwaną sztuczką jądra, w której jądro zajmuje mało wymiarową przestrzeń wejściową i przekształca ją w wyższą przestrzeń wymiarową. W prostych słowach, jądro przekształca nierozdzielne problemy w oddzielne problemy, dodając do nich więcej wymiarów. To sprawia, że ​​SVM jest bardziej wydajne, elastyczne i dokładne. Poniżej przedstawiono niektóre typy jąder używanych przez SVM -

Linear Kernel

Może być używany jako iloczyn skalarny między dowolnymi dwoma obserwacjami. Wzór jądra liniowego jest następujący -

k (x, x i ) = suma (x * x i )

Z powyższego wzoru widzimy, że iloczyn między dwoma wektorami mówi & jest sumą mnożenia każdej pary wartości wejściowych.

Jądro wielomianowe

Jest to bardziej uogólniona forma jądra liniowego i rozróżnia zakrzywioną lub nieliniową przestrzeń wejściową. Poniżej znajduje się wzór na jądro wielomianowe -

K (x, xi) = 1 + suma (x * xi) ^ d

Tutaj d jest stopniem wielomianu, który musimy określić ręcznie w algorytmie uczącym.

Kernel Radial Basis Function (RBF)

Jądro RBF, najczęściej używane w klasyfikacji SVM, odwzorowuje przestrzeń wejściową w nieokreślonej przestrzeni wymiarowej. Poniższy wzór wyjaśnia to matematycznie -

K (x, xi) = exp (-gamma * suma ((x - xi ^ 2))

Tutaj gamma mieści się w zakresie od 0 do 1. Musimy ręcznie określić to w algorytmie uczącym. Dobra domyślna wartość gamma to 0,1.

Ponieważ zaimplementowaliśmy SVM dla danych, które można rozdzielić liniowo, możemy zaimplementować je w Pythonie dla danych, których nie można rozdzielić liniowo. Można to zrobić za pomocą jądra.

Przykład

Poniżej znajduje się przykład tworzenia klasyfikatora SVM przy użyciu jądra. Będziemy używać zestawu danych tęczówki ze scikit-learn -

Zaczniemy od importu następujących pakietów -

import pandas as pd
import numpy as np
from sklearn import svm, datasets
import matplotlib.pyplot as plt

Teraz musimy załadować dane wejściowe -

iris = datasets.load_iris()

Z tego zbioru danych bierzemy pierwsze dwie cechy w następujący sposób -

X = iris.data[:, :2]
y = iris.target

Następnie wykreślimy granice SVM z oryginalnymi danymi w następujący sposób -

x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
h = (x_max / x_min)/100
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
   np.arange(y_min, y_max, h))
X_plot = np.c_[xx.ravel(), yy.ravel()]

Teraz musimy podać wartość parametru regularyzacji w następujący sposób -

C = 1.0

Następnie można utworzyć obiekt klasyfikatora SVM w następujący sposób -

Svc_classifier = svm.SVC (kernel = 'linear', C = C). Fit (X, y)

Z = svc_classifier.predict(X_plot)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(xx, yy, Z, cmap=plt.cm.tab10, alpha=0.3)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('Support Vector Classifier with linear kernel')

Wynik

Text(0.5, 1.0, 'Support Vector Classifier with linear kernel')

Do tworzenia klasyfikatora SVM z rbf kernel, możemy zmienić jądro na rbf w następujący sposób -

Svc_classifier = svm.SVC(kernel='rbf', gamma =‘auto’,C=C).fit(X, y)
Z = svc_classifier.predict(X_plot)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(xx, yy, Z, cmap=plt.cm.tab10, alpha=0.3)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('Support Vector Classifier with rbf kernel')

Wynik

Text(0.5, 1.0, 'Support Vector Classifier with rbf kernel')

Ustawiamy wartość gamma na „auto”, ale możesz również podać jej wartość z zakresu od 0 do 1.

Plusy i minusy klasyfikatorów SVM

Zalety klasyfikatorów SVM

Klasyfikatory SVM zapewniają dużą dokładność i dobrze współpracują z dużą przestrzenią wymiarową. Klasyfikatory SVM zasadniczo wykorzystują podzbiór punktów szkoleniowych, dlatego w rezultacie zużywają bardzo mniej pamięci.

Wady klasyfikatorów SVM

Mają długi czas szkolenia, dlatego w praktyce nie nadają się do dużych zbiorów danych. Inną wadą jest to, że klasyfikatory SVM nie działają dobrze z nakładającymi się klasami.