Машина опорных векторов (SVM) – это тип алгоритма классификации машинного обучения с учителем. SVM были впервые представлены в 1960-х годах, а затем были усовершенствованы в 1990-х годах. Однако только сейчас они становятся чрезвычайно популярными благодаря своей способности достигать блестящих результатов. SVM реализованы уникальным способом по сравнению с другими алгоритмами машинного обучения.
В этой статье мы увидим, что такое алгоритмы опорных векторных машин, краткую теорию опорных векторных машин и их реализацию в библиотеке Python Scikit-Learn. Затем мы перейдем к расширенной концепции SVM, известной как Kernel SVM, а также реализуем ее с помощью Scikit-Learn.
Простая SVM
В случае линейно разделяемых данных в двух измерениях, как показано на рисунке, типичный алгоритм машинного обучения пытается найти границу, которая разделяет данные таким образом, чтобы можно было минимизировать ошибку неправильной классификации. Если вы внимательно посмотрите на рисунок, то может быть несколько границ, которые правильно разделяют точки данных. Две пунктирные линии, а также одна сплошная линия правильно классифицируют данные.

SVM отличается от других алгоритмов классификации тем, что он выбирает границу решения, которая максимизирует расстояние от ближайших точек данных всех классов. SVM не просто находит границу принятия решения, он находит наиболее оптимальную границу решения.
Самая оптимальная граница решения – это та, которая имеет максимальный запас от ближайших точек всех классов. Ближайшие точки от границы решения, которые максимизируют расстояние между границей решения и точками, называются опорными векторами. Граница решения в случае машин с опорными векторами называется классификатором максимальной маржи или гиперплоскостью максимальной маржи.

За поиском векторов поддержки, вычислением разницы между границей решения и векторами поддержки и максимизацией этой разницы стоит сложная математика. В этом руководстве мы не будем вдаваться в детали математики, мы скорее увидим, как SVM и Kernel SVM реализуются через библиотеку Python Scikit-Learn.
Реализация SVM
Набор данных, который мы собираемся использовать в этом разделе, тот же, что мы использовали в разделе классификации в руководстве по дереву решений.
Наша задача состоит в том, чтобы предсказать, является ли банкнота подлинной или нет, на основе четырех атрибутов банкноты, т.е. асимметрии изображения, преобразованного вейвлет, дисперсии изображения, энтропии изображения и краткости изображения. Это проблема двоичной классификации, и мы будем использовать алгоритм SVM для решения этой проблемы. Остальная часть раздела состоит из стандартных шагов машинного обучения.
Импорт библиотек
Следующий скрипт импортирует необходимые библиотеки:
import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline
Импорт набора данных
Загрузите набор данных на Google Диск и сохраните его локально на своем компьютере. В этом примере CSV-файл для набора данных хранится в папке «Datasets» на диске D на моем компьютере с Windows. Скрипт читает файл по этому пути. Вы можете соответствующим образом изменить путь к файлу на вашем компьютере.
Чтобы прочитать данные из файла CSV, самый простой способ – использовать метод read_csv библиотеки pandas. Следующий код считывает данные банкнот в фреймворке pandas:
bankdata = pd.read_csv("D:/Datasets/bill_authentication.csv")
Исследовательский анализ данных
Существует практически безграничное количество способов анализа наборов данных с помощью различных библиотек в Python. Для простоты мы проверим только размеры данных и увидим первые несколько записей. Чтобы увидеть строки и столбцы, а также данные, выполните следующую команду:
bankdata.shape
В выводе вы увидите (1372,5). Это означает, что набор данных банкноты состоит из 1372 строк и 5 столбцов.
Чтобы понять, как на самом деле выглядит наш набор данных, выполните следующую команду:
bankdata.head()
Результат будет выглядеть так:
| Дисперсия | Асимметрия | Куртоз | Энтропия | Класс | |
|---|---|---|---|---|---|
| 0 | 3,62160 | 8,6661 | -2.8073 | -0,44699 | 0 |
| 1 | 4,54590 | 8,1674 | -2,4586 | -1,46210 | 0 |
| 2 | 3,86600 | -2,6383 | 1,9242 | 0,10645 | 0 |
| 3 | 3,45660 | 9,5228 | -4,0112 | -3,59440 | 0 |
| 4 | 0,32924 | -4,4552 | 4,5718 | -0,98880 | 0 |
Вы можете видеть, что все атрибуты в наборе данных являются числовыми. Метка также числовая, то есть 0 и 1.
Предварительная обработка данных
Предварительная обработка данных включает в себя (1) разделение данных на атрибуты и метки и (2) разделение данных на наборы для обучения и тестирования.
Чтобы разделить данные на атрибуты и метки, выполните следующий код:
X = bankdata.drop('Class', axis=1)
y = bankdata['Class']
В первой строке приведенного выше сценария все столбцы фрейма данных bankdata сохраняются в переменной X, за исключением столбца «Класс», который является столбцом метки. Метод drop() удаляет этот столбец.
Во второй строке в переменной y сохраняется только столбец класса. На данный момент переменная X содержит атрибуты, а переменная y содержит соответствующие метки.
После того, как данные разделены на атрибуты и метки, последним шагом предварительной обработки является разделение данных на обучающие и тестовые наборы. К счастью, библиотека model_selection библиотеки Scikit-Learn содержит метод train_test_split, который позволяет нам легко разделять данные на обучающие и тестовые наборы.
Для этого выполните следующий скрипт:
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)
Обучение алгоритму
Мы разделили данные на обучающие и тестовые наборы. Пришло время обучить нашу SVM на обучающих данных. Scikit-Learn содержит библиотеку svm, которая содержит встроенные классы для различных алгоритмов SVM. Поскольку мы собираемся выполнить задачу классификации, мы будем использовать класс классификатора опорных векторов, который записан как SVC в библиотеке svm Scikit-Learn. Этот класс принимает один параметр – тип ядра. Это очень важно. В случае простой SVM мы просто устанавливаем этот параметр как «linear», поскольку простые SVM могут классифицировать только линейно разделяемые данные. Мы увидим нелинейные ядра в следующем разделе.
Метод соответствия класса SVC вызывается для обучения алгоритма на обучающих данных, которые передаются в качестве параметра методу соответствия. Выполните следующий код для обучения алгоритма:
from sklearn.svm import SVC svclassifier = SVC(kernel='linear') svclassifier.fit(X_train, y_train)
Прогнозы
Для прогнозирования используется метод прогнозирования класса SVC. Взгляните на следующий код:
y_pred = svclassifier.predict(X_test)
Оценка алгоритма
Матрица неточностей, точность, отзыв и меры F1 являются наиболее часто используемыми метриками для задач классификации. Библиотека показателей Scikit-Learn содержит методы классификации_report и confusion_matrix, которые можно легко использовать для определения значений этих важных показателей.
Вот код для поиска этих показателей:
from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test,y_pred)) print(classification_report(y_test,y_pred))
Полученные результаты
Результаты оценки следующие:
[[152 0]
[ 1 122]]
precision recall f1-score support
0 0.99 1.00 1.00 152
1 1.00 0.99 1.00 123
avg / total 1.00 1.00 1.00 275
Из результатов видно, что SVM немного превзошел алгоритм дерева решений. Есть только одна ошибочная классификация в случае алгоритма SVM по сравнению с четырьмя ошибками в случае алгоритма дерева решений.
Ядро SVM
В предыдущем разделе мы увидели, как можно использовать простой алгоритм SVM, чтобы найти границу решения для линейно разделяемых данных. Однако в случае нелинейно разделяемых данных, таких как показанные на рисунке, прямая линия не может использоваться в качестве границы принятия решения.

В случае нелинейно разделяемых данных простой алгоритм SVM не может быть использован. Вместо этого используется модифицированная версия SVM, называемая Kernel SVM.
По сути, SVM ядра проецирует нелинейно разделяемые данные более низких измерений на линейно разделяемые данные более высоких измерений таким образом, что точки данных, принадлежащие разным классам, распределяются по разным измерениям. Опять же, здесь задействована сложная математика, но вам не нужно беспокоиться об этом, чтобы использовать SVM. Скорее мы можем просто использовать библиотеку Python Scikit-Learn для реализации и использования SVM ядра.
Реализация Kernel SVM
Реализация Kernel SVM с помощью Scikit-Learn аналогична простой SVM. В этом разделе мы будем использовать известный набор данных радужной оболочки глаза, чтобы предсказать категорию, к которой принадлежит растение, на основе четырех атрибутов: ширина чашелистика, длина чашелистика, ширина лепестка и длина лепестка.
Остальные шаги являются типичными шагами машинного обучения и требуют очень небольшого объяснения, пока мы не дойдем до той части, где мы обучаем нашу SVM ядра.
Импорт библиотек
import numpy as np import matplotlib.pyplot as plt import pandas as pd
Импорт набора данных
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data" # Assign colum names to the dataset colnames = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'Class'] # Read dataset to pandas dataframe irisdata = pd.read_csv(url, names=colnames)
Предварительная обработка
X = irisdata.drop('Class', axis=1)
y = irisdata['Class']
Тестовый сплит
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)
Обучение алгоритму
Для обучения SVM ядра мы используем тот же класс SVC библиотеки svm Scikit-Learn. Разница заключается в значении параметра ядра класса SVC. В случае простой SVM мы использовали «linear» в качестве значения параметра ядра. Однако для ядра SVM вы можете использовать гауссово, полиномиальное, сигмоидальное или вычислимое ядро. Мы их реализуем, чтобы увидеть, какое из них лучше подходит для нашей задачи.
1. Полиномиальное ядро
В случае полиномиального ядра вы также должны передать значение параметра степени класса SVC. Это в основном степень многочлена. Посмотрите, как мы можем использовать полиномиальное ядро для реализации SVM ядра:
from sklearn.svm import SVC svclassifier = SVC(kernel='poly', degree=8) svclassifier.fit(X_train, y_train)
Прогнозы
Теперь, когда мы обучили алгоритм, следующий шаг – сделать прогнозы на основе тестовых данных.
Для этого выполните следующий сценарий:
y_pred = svclassifier.predict(X_test)
Оценка алгоритма
Как обычно, последний шаг любого алгоритма машинного обучения – это вычисление полиномиального ядра. Выполните следующий скрипт:
from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred))
Выходные данные для ядра SVM с полиномиальным ядром выглядят следующим образом:
[[11 0 0]
[ 0 12 1]
[ 0 0 6]]
precision recall f1-score support
Iris-setosa 1.00 1.00 1.00 11
Iris-versicolor 1.00 0.92 0.96 13
Iris-virginica 0.86 1.00 0.92 6
avg / total 0.97 0.97 0.97 30
Теперь давайте повторим те же шаги для гауссовского и сигмовидного ядер.
2. Ядро Гаусса
Посмотрите, как мы можем использовать полиномиальное ядро для реализации SVM ядра:
from sklearn.svm import SVC svclassifier = SVC(kernel='rbf') svclassifier.fit(X_train, y_train)
Чтобы использовать ядро Гаусса, вы должны указать ‘rbf’ в качестве значения для параметра ядра класса SVC.
Прогнозирование и оценка
y_pred = svclassifier.predict(X_test)
from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred))
Результат Kernel SVM с гауссовым ядром выглядит так:
[[11 0 0]
[ 0 13 0]
[ 0 0 6]]
precision recall f1-score support
Iris-setosa 1.00 1.00 1.00 11
Iris-versicolor 1.00 1.00 1.00 13
Iris-virginica 1.00 1.00 1.00 6
avg / total 1.00 1.00 1.00 30
3. Сигмовидное ядро
Наконец, давайте использовать сигмоидное ядро для реализации Kernel SVM. Взгляните на следующий скрипт:
from sklearn.svm import SVC svclassifier = SVC(kernel='sigmoid') svclassifier.fit(X_train, y_train)
Чтобы использовать сигмоидное ядро, вы должны указать «сигмоид» в качестве значения для параметра ядра класса SVC.
Прогнозирование и оценка
y_pred = svclassifier.predict(X_test)
from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred))
Выходные данные Kernel SVM с ядром Sigmoid выглядят следующим образом:
[[ 0 0 11]
[ 0 0 13]
[ 0 0 6]]
precision recall f1-score support
Iris-setosa 0.00 0.00 0.00 11
Iris-versicolor 0.00 0.00 0.00 13
Iris-virginica 0.20 1.00 0.33 6
avg / total 0.04 0.20 0.07 30
Сравнение производительности ядра
Если мы сравним производительность разных типов ядер, мы ясно увидим, что сигмовидное ядро работает хуже всего. Это связано с тем, что сигмовидная функция возвращает два значения, 0 и 1, поэтому она больше подходит для задач двоичной классификации. Однако в нашем случае у нас было три выходных класса.
Среди гауссовского ядра и полиномиального ядра мы можем видеть, что гауссовское ядро достигло идеальной 100% скорости предсказания, в то время как полиномиальное ядро неверно классифицировало один экземпляр. Поэтому гауссово ядро работало немного лучше. Однако не существует жесткого правила, определяющего, какое ядро лучше всего работает в каждом сценарии. Все дело в тестировании всех ядер и выборе того, которое дает наилучшие результаты в вашем тестовом наборе данных.
Заключение
В этой статье мы изучили, как простые, так и ядерные SVM. Мы изучили интуицию алгоритма SVM и то, как его можно реализовать с помощью библиотеки Scikit-Learn в Python. Мы также изучили различные типы ядер, которые можно использовать для реализации SVM ядра. Я предлагаю вам попробовать реализовать эти алгоритмы на реальных наборах данных, доступных на таких сайтах, как kaggle.com.
Я также предлагаю вам изучить фактическую математику, лежащую в основе SVM. Хотя вам не обязательно это понадобится для использования алгоритма SVM, все же очень удобно знать, что на самом деле происходит за сценой, пока ваш алгоритм находит границы решения.