Обзор

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

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

Понимание SVM

Для этого урока мы будем использовать набор данных iris, предоставленный sklearn. Ниже показан код для загрузки набора данных, его описание и изображение, чтобы понять атрибуты «лепесток» и «чашелистик», которые он описывает.

import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()

print(dir(iris))
print(iris.DESCR)

Первое, что мы хотим сделать, это поместить все эти данные в кадр данных pandas, чтобы лучше понять, с чем мы работаем. В приведенном ниже коде мы создаем фрейм данных, добавляем столбец с именем цветка, который применяет лямбда-функцию, именующую каждую строку на основе значения, которое она имеет в целевом столбце, и печатает первый, второй и третий наборы данных в фрейме данных.

Мы видим, что первые 50 рядов относятся к цветку сетоза, следующие 50 — к цветку лишай, а последние 50 рядов — к цветку виргиника.

df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['target'] = iris.target

df['flower_name'] =df.target.apply(lambda x: iris.target_names[x])

print(df[:50].head())
print(df[51:99].head())
print(df[100:].head())

Давайте нарисуем наши данные, чтобы визуализировать их. Я собираюсь разделить данные на 3 разных фрейма данных, соответствующих каждому уникальному цветку.

import matplotlib.pyplot as plt

setosa_df = df[:50]
versicolor_df = df[50:100]
virginica_df = df[100:]

plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.scatter(setosa_df['sepal length (cm)'], setosa_df['sepal width (cm)'],color="green",marker='+')
plt.scatter(versicolor_df['sepal length (cm)'], versicolor_df['sepal width (cm)'],color="blue",marker='.')

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

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

На приведенном выше графике мы видим, что каждая точка данных имеет границу (выделенную красным) между ней и границей классификации. Нам нужна линия, которая максимизирует это расстояние.

Эти точки данных рядом с линией называются «опорными векторами», отсюда и название машины опорных векторов.

В случае, если у нас есть только 2 объекта, как на графике выше, граница представляет собой линию. Но в случае трех объектов граница представляет собой плоскость.

А теперь представьте, что есть более 3 объектов... хотя было бы невозможно создать изображение, позволяющее нам его визуализировать, математически это все же возможно, и граница будет называться гиперплоскостью.

Окончательное определение SVM:Машины опорных векторов рисуют гиперплоскость в n-мерном пространстве таким образом, чтобы максимизировать разрыв между классификационными группами

Гамма и регуляризация

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

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

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

Ни один из вариантов не является более правильным, это просто зависит от вашей конкретной ситуации.

Гамма — это гиперпараметр, который мы должны установить при построении нашей модели.

C — гиперпараметр для регуляризации. Параметр c компенсирует правильную классификацию обучающих примеров максимизацией запаса решающей функции.

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

Ниже представлена ​​тепловая карта, найденная на веб-сайте sklearn, демонстрирующая взаимосвязь между гаммой и c.

Мы оптимизируем эти значения, выполнив так называемый поиск по сетке, о котором мы поговорим позже.

Построение нашей модели

В приведенном ниже коде мы импортируем класс SVM из sklearn, разделяем наши данные на X/Y и обучающие/тестовые наборы, строим нашу модель со значением C, равным 2, и значением gamme, равным 10, для начала и проверяем оценку нашей модели. В итоге мы получаем 0,93 балла, что является солидным показателем.

Кстати, у sklearn есть автоматические значения, которые можно использовать для C и гаммы, если мы не указываем их явно.

from sklearn.model_selection import train_test_split
from sklearn.svm import SVC

x = df.drop(['target','flower_name'], axis='columns')
y = df.target

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

model = SVC(C =2, gamma=10)

model.fit(x_train, y_train)

model.score(x_test, y_test)

.93 отлично, но мы можем использовать класс поиска по сетке sklearn, чтобы вычислить еще лучшие значения для гаммы и C.

import numpy as np
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.model_selection import GridSearchCV

# logspace: create an array of evenly spaced values between two numbers on the logarithmic scale
C_range = np.logspace(-2, 10, 13)
gamma_range = np.logspace(-9, 3, 13)

param_grid = dict(gamma=gamma_range, C=C_range)

cv = StratifiedShuffleSplit(n_splits=5, test_size=0.2, random_state=42)

grid = GridSearchCV(SVC(), param_grid=param_grid, cv=cv)

grid.fit(x_train, y_train)

print(
    "The best parameters are %s with a score of %0.2f"
    % (grid.best_params_, grid.best_score_)
)

И точно так же у нас есть полностью оптимизированная модель машины опорных векторов для классификации видов цветов на основе ширины и высоты лепестков и чашелистиков.