Рубрики
Без рубрики

Реализация SVM и ядра SVM с помощью Python Scikit-Learn

Автор оригинала: Usman Malik.

Реализация SVM и ядра SVM с помощью Python Scikit-Learn

A support vector machine (SVM) – это тип алгоритма классификации управляемого машинного обучения. SVM были введены первоначально в 1960-х годах, а затем были усовершенствованы в 1990-х годах. Однако только сейчас они становятся чрезвычайно популярными благодаря своей способности достигать блестящих результатов. SVM реализуются уникальным образом по сравнению с другими алгоритмами машинного обучения.

В этой статье мы рассмотрим, что такое алгоритмы машин опорных векторов, краткую теорию, лежащую в основе машины опорных векторов, и их реализацию в библиотеке Scikit-Learn Python. Затем мы перейдем к продвинутой концепции SVM, известной как Kernel SVM, а также реализуем ее с помощью Scikit-Learn.

Простой SVM

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

Множественные Границы Принятия Решений

Рис. 1: Множественные Границы Принятия Решений

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

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

Граница принятия решения с опорными векторами

Рис. 2: Граница принятия решения с опорными векторами

Существует сложная математика, связанная с поиском опорных векторов, вычислением маржи между границей принятия решения и опорными векторами и максимизацией этой маржи. В этом уроке мы не будем вдаваться в подробности математики, а скорее посмотрим, как SVM и Kernel SVM реализуются с помощью библиотеки Python Scikit-Learn.

Реализация SVM с помощью Scikit-Learn

Набор данных, который мы будем использовать в этом разделе, совпадает с тем, который мы использовали в разделе классификации учебника “Дерево решений”.

Наша задача состоит в том, чтобы предсказать, является ли банкнота подлинной или нет, основываясь на четырех атрибутах банкноты: асимметрии вейвлет-преобразованного изображения, дисперсии изображения, энтропии изображения и куртозе изображения. Это проблема бинарной классификации, и мы будем использовать алгоритм SVM для решения этой проблемы. Остальная часть раздела состоит из стандартных шагов машинного обучения.

Импорт библиотек

Следующий скрипт импортирует необходимые библиотеки:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

Импорт набора данных

Данные доступны для скачивания по следующей ссылке:

Данные доступны для скачивания по следующей ссылке:

Подробная информация о данных доступна по следующей ссылке:

Подробная информация о данных доступна по следующей ссылке:

Загрузите набор данных по ссылке Google Drive и сохраните его локально на своем компьютере. В этом примере 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 -0.44699 -2.8073 8.6661 3.62160 0
0 -1.46210 -2.4586 8.1674 4.54590 1
0 0.10645 1.9242 -2.6383 3.86600 2
0 -3.59440 -4.0112 9.5228 3.45660 3
0 -0.98880 4.5718 -4.4552 0.32924 4

Вы можете видеть, что все атрибуты в наборе данных являются числовыми. Метка также является числовой, то есть 0 и 1.

Предварительная обработка данных

Предварительная обработка данных включает в себя (1) Разделение данных на атрибуты и метки и (2) разделение данных на обучающие и тестовые наборы.

Чтобы разделить данные на атрибуты и метки, выполните следующий код:

X = bankdata.drop('Class', axis=1)
y = bankdata['Class']

В первой строке приведенного выше скрипта все столбцы фрейма данных bank data хранятся в переменной X , за исключением столбца “Class”, который является столбцом label. Метод drop() отбрасывает этот столбец.

Во второй строке в переменной y хранится только столбец class. В этот момент времени переменная 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 в библиотеке Scikit-Learn svm . Этот класс принимает один параметр, который является типом ядра. Это очень важно. В случае простой SVM мы просто устанавливаем этот параметр как “линейный”, так как простые SVM могут классифицировать только линейно разделимые данные. Нелинейные ядра мы увидим в следующем разделе.

Метод fit класса SVC вызывается для обучения алгоритма на обучающих данных, которые передаются в качестве параметра методу fit . Выполните следующий код для обучения алгоритма:

from sklearn.svm import SVC
svclassifier = SVC(kernel='linear')
svclassifier.fit(X_train, y_train)

Делать Прогнозы

Для выполнения прогнозов используется метод predict класса SVC . Взгляните на следующий код:

y_pred = svclassifier.predict(X_test)

Оценка алгоритма

Матрица путаницы, точность, отзыв и показатели F1 являются наиболее часто используемыми метриками для задач классификации. Библиотека Scikit-Learn metrics содержит методы classification_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 может быть использован для нахождения границы решения для линейно разделимых данных. Однако в случае нелинейно разделимых данных, таких как показанные на рис. 3, прямая линия не может быть использована в качестве границы принятия решения.

Нелинейно разделяемые данные

Рис. 3: Нелинейно Разделяемые данные

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

В основном ядро SVM проецирует нелинейно разделяемые данные нижних измерений на линейно разделяемые данные более высоких измерений таким образом, что точки данных, принадлежащие к разным классам, распределяются по разным измерениям. Опять же, в этом есть сложная математика, но вам не нужно беспокоиться об этом, чтобы использовать SVM. Скорее всего, мы можем просто использовать библиотеку Scikit-Learn Python для реализации и использования SVM ядра.

Реализация SVM ядра с помощью Scikit-Learn

Реализация SVM ядра с помощью Scikit-Learn аналогична простой SVM. В этом разделе мы будем использовать знаменитый набор данных iris для прогнозирования категории, к которой относится растение, на основе четырех атрибутов: ширина чашелистика, длина чашелистика, ширина лепестка и длина лепестка.

Набор данных можно загрузить по следующей ссылке:

Набор данных можно загрузить по следующей ссылке:

Остальные шаги являются типичными шагами машинного обучения и нуждаются в очень небольшом объяснении, пока мы не достигнем той части, где мы тренируем наше ядро 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 библиотеки Scikit-Learn svm . Разница заключается в значении параметра ядра класса SVC . В случае простого SVM мы использовали “линейный” в качестве значения параметра ядра. Однако для SVM ядра вы можете использовать гауссово, полиномиальное, сигмоидное или совместимое ядро. Мы реализуем полиномиальные, гауссовские и сигмоидные ядра, чтобы увидеть, какое из них лучше подходит для нашей задачи.

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

В случае полиномиального ядра вы также должны передать значение для параметра degree класса SVC . Это в основном степень многочлена. Взгляните на то, как мы можем использовать полиномиальное ядро для реализации kernel 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. Гауссово ядро

Взгляните на то, как мы можем использовать полиномиальное ядро для реализации kernel 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))

Вывод ядра 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)

Чтобы использовать сигмоидное ядро, вы должны указать ‘sigmoid’ в качестве значения для параметра kernel класса 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))

Вывод ядра SVM с сигмоидным ядром выглядит следующим образом:

[[ 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, Scikit-Learn и других полезных алгоритмах машинного обучения? Я бы рекомендовал проверить некоторые более подробные ресурсы, например одну из этих книг:

Вывод

В этой статье мы изучали как простые, так и ядерные SVM. Мы изучили интуицию, лежащую в основе алгоритма SVM, и то, как он может быть реализован с помощью библиотеки Scikit-Learn Python. Мы также изучили различные типы ядер, которые могут быть использованы для реализации SVM ядра. Я бы посоветовал вам попробовать реализовать эти алгоритмы на реальных наборах данных, доступных в таких местах, как kaggle.com .

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