Обзор
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_) )
И точно так же у нас есть полностью оптимизированная модель машины опорных векторов для классификации видов цветов на основе ширины и высоты лепестков и чашелистиков.