Все ссылки взяты из книги Hands On Machine Learning with Scikit-learn, Keras & Tensorflow Орельена Герона. Блокнот для этой статьи можно найти здесь.

Машины опорных векторов можно использовать для линейной или нелинейной классификации, регрессии и даже обнаружения выбросов. Он хорошо подходит для сложных небольших или средних наборов данных. SVM также чувствительны к масштабированию функций, если функция стандартизирована, она будет лучше обобщаться. Классификатор SVM также не выводит вероятности классов.

Линейный метод опорных векторов

Линейный SVM можно рассматривать как улицу, проходящую через данные и разделяющую два класса по обеим сторонам. SVM с жесткими границами можно использовать, когда данные линейно разделимы, но они также чувствительны к выбросам. Жесткая маржа строго следит за тем, чтобы все точки данных были разделены улицей, что не является хорошим обобщением. Однако SVM с мягкой маржой позволяют некоторым классам находиться внутри улицы. В scikit-learn мы можем использовать параметр «C», чтобы найти баланс между мягкими и жесткими полями. Более высокое значение C делает улицу уже, а более низкое значение делает ее шире.

## Linear SVM Classifier
import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
# load dataset
iris = datasets.load_iris()
X = iris["data"][:, (2, 3)] # petal length, petal width
y = (iris["target"] == 2).astype(np.float) # Iris virginica

svm_clf = Pipeline([
("scaler", StandardScaler()),
("linear_svc", LinearSVC(C=1, loss="hinge"))
])
svm_clf.fit(X, y)
print(svm_clf.predict([[5, 4]]))

Обработка нелинейных данных с помощью линейного SVM

Мы можем обрабатывать нелинейные данные с любой линейной моделью, добавляя больше полиномиальных признаков, чтобы данные стали линейно разделимыми. Однако для сложных и огромных наборов данных этот подход не будет работать, поскольку он сделает модели медленнее, вместо этого мы должны использовать SVM с полиномиальным ядром.

## Linear SVM Classifier with non-linear data
from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
X, y = make_moons(n_samples=100, noise=0.15)
poly_svm_clf = Pipeline([
("poly_features", PolynomialFeatures(degree=3)),
("scaler", StandardScaler()),
("svm_clf", LinearSVC(C=10, loss="hinge"))
])
poly_svm_clf.fit(X, y)

Полиномиальное ядро

Для сложных и огромных нелинейных наборов данных вы можете использовать полиномиальные ядра. Трюк с ядром дает тот же результат, что и при добавлении полиномиальных функций. Если модель недостаточно подходит, попробуйте увеличить степень, а если она подходит, уменьшите степень. Кроме того, гиперпараметр «coef0» контролирует, насколько на модель влияют полиномы степени по сравнению с полиномами низкой степени.

from sklearn.svm import SVC
poly_kernel_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=5)
)]

SVM-регрессия

Для задач регрессии мы делаем противоположное тому, что мы делали в классификации. Вместо того, чтобы разделять два класса, на этот раз мы пытаемся разместить все точки внутри улицы. Ширина поля контролируется гиперпараметром эпсилон. Подобно классификации, SVM также может использоваться для нелинейной регрессии с использованием полиномиальных признаков.

from sklearn.svm import SVR
svm_reg = SVR(kernel="poly", degree=2, C=100, epsilon=0.1)
svm_reg.fit(X, y)

Под капотом

В линейном SVM мы просто предсказываем класс в зависимости от вывода следующего равенства — (w*x + b ‹ 0), затем класс 0 и если › 0 класс 1. Обе задачи жесткой и мягкой маржи представляют собой задачи выпуклой квадратичной оптимизации с линейной ограничения. Как работает трюк с ядром? Например, если вы используете полиномиальное ядро, вместо того, чтобы применять преобразование ко всем обучающим образцам, вы заменяете скалярное произведение этих векторов (x * b) на его квадрат, и результаты остаются прежними и экономят много времени. вычисление.

Потеря петли

Функция «max (0, 1-t)» называется функцией потери шарнира. Он равен 0, когда t≥1. Его наклон равен -1, если t‹1, и 0, если t›1. Он не дифференцируем при t=0.

Могут ли SVM предсказывать вероятности?

Классификатор SVM может вывести расстояние между тестовым экземпляром и границей решения, и вы можете использовать его в качестве показателя достоверности. Однако эта оценка не может быть напрямую преобразована в оценку вероятности класса. Если при создании SVM в Scikit-Learn вы зададите вероятность=True, то после обучения он будет калибровать вероятности с помощью логистической регрессии на основе показателей SVM (обученных дополнительной пятикратной перекрестной проверкой обучающих данных). Это добавит в SVM метод predict_proba.

Упражнение 1. Обучите LinearSVC на наборе линейных разделимых данных. Обучите SVC и SGDClassifier на одном и том же наборе данных. Посмотрите, сможете ли вы заставить их производить примерно одну и ту же модель.

Я смог обучить и LinearSVC, и SVC, но не смог сравнить границы обоих, мне все еще нужно изучить продвинутые методы построения графиков. Но для решения вы можете обратиться сюда. В нем есть весь код уроков, а также решения для всех упражнений.

Упражнение 2: обучение и SVM-классификатор на наборе данных MNIST. Поскольку классификаторы SVM являются двоичными, вам, возможно, придется использовать один против остальных, чтобы классифицировать все 10 цифр. Настройте гиперпараметры, какой точности вы можете достичь?

Используя load_digits в scikit-learn lib, я наткнулся на очень гладкий код для создания сетки графиков matplotlib для отображения образцов изображений.

## Load dataset
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
digits = load_digits()
print(digits.keys())
# plot some images
_, axes = plt.subplots(nrows=1, ncols=4, figsize=(10, 3))
for ax, image, label in zip(axes, digits.images, digits.target):
ax.set_axis_off()
ax.imshow(image, cmap=plt.cm.gray_r)
ax.set_title('Training label: %i' %label)

Упражнение 3: обучение регрессора SVM на наборе данных California Housing

## Rregression
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn import svm
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import reciprocal, uniform
# data
housing = fetch_california_housing()
X = housing["data"]
y = housing["target"]
# splitting data
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.1, shuffle=True)
# scaling the data
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_val_scaled = scaler.transform(X_val)
# Linear SVR model
svm_reg = svm.LinearSVR(random_state=42)
svm_reg.fit(X_train_scaled, y_train)
# evaluate
preds = svm_reg.predict(X_val_scaled)
print("Linear SVR RMSE", np.sqrt(mean_squared_error(preds, y_val)))
# tune hyperparameter of SVR
param_distributions = {"gamma": reciprocal(0.001, 0.1), "C": uniform(1, 10)}
rnd_cv_reg = RandomizedSearchCV(svm.SVR(), param_distributions, n_iter=10, cv=3, random_state=42)
rnd_cv_reg.fit(X_train_scaled, y_train)
print(rnd_cv_reg.best_estimator_, rnd_cv_reg.best_score_)