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

В основном в машинном обучении формулировки задач, которые мы получаем, могут быть проанализированы/решены с использованием 4 типов алгоритмов:

  • Классификация
  • Регрессия
  • Кластеризация
  • Уменьшение размерности

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

Чтобы понять алгоритм SVM, мы должны быть знакомы с некоторыми ключевыми терминами, которые с ним связаны. Сам SVM является частью классификатора, известного как классификатор опорных векторов или SVC. Точно так же существует регрессор с именем Support Vector Regression SVR, который используется для задач регрессии.

Теперь, когда выбрать этот алгоритм? Как показано на изображении выше, если количество выборок (наблюдение) меньше 100 тыс., Сначала мы выберем линейный SVC, а если он не работает, поскольку у нас есть текстовые данные, мы перейдем к классификатору KNeighbors и SVC. Если это все еще не работает должным образом, мы будем использовать метод ансамбля, который объединяет несколько алгоритмов для достижения результата. С другой стороны, если данные не текстовые, мы можем выбрать алгоритмы NaiveBayes. Также, если количество выборок превышает 100 тыс., мы будем пробовать классификатор SGD с приближением ядра.

Типы SVM:

Существует два типа SVM, каждый из которых используется для разных ситуаций:

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

Следует отметить, что Simple SVM также является SVM ядра, но со значением kernal=’linear’.

Принцип работы:

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

Давайте увеличим размерность данных. Они будут представлены с использованием координатной плоскости, которая является двухмерной координатной плоскостью и может быть разделена линией. Следовательно, если нам нужно классифицировать данные, мы должны разделить эти классы на две части, и для этого нам нужна линия, которая пересекает координатную плоскость. Если мы продолжим увеличивать размерность данных и представлять данные в трехмерных координатах, для разделения классов нам понадобится двумерная плоскость и так далее. Эту идею можно распространить и на N-меры. Таким образом, N-мерный гиперкуб можно классифицировать с помощью гиперплоскости.

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

Эта линия называется границей, а ближайшие экземпляры по обе стороны границы называются опорными векторами. Это точки, которые дали этому алгоритму классификации его имя, машины опорных векторов. Не всегда возможно иметь жесткую границу решения, которая четко разделяет точки данных. Следовательно, у нас есть два типа полей вокруг границы — Жесткие поля и Мягкие поля. Классификаторы с жесткими границами чувствительны к выбросам и требуют совершенно линейной разделимости данных и не допускают выбросов, тогда как классификаторы с мягкими границами допускают некоторые нарушения границ решения. Таким образом, в зависимости от того, допускает ли ваша машина опорных векторов выбросы, у нас может быть классификация с жесткими полями или классификация с мягкими полями.

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

На этом изображении к этим данным применено преобразование X в квадрате. После чего преобразованные данные могут быть линейно разделены прямой линией, и мы можем использовать SVM с этими точками. Это преобразование в квадрат X — наш трюк с ядром.

Давайте используем их, чтобы предсказать живучесть корабля «Титаник». Мы импортируем необходимые пакеты, такие как sklearn, pandas, matploitlib и seaborn.

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score

from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import SGDClassifier
from sklearn.svm import LinearSVC

Мы загрузим данные и обработаем их, удалив ненужные значения и нулевые значения.

titanic_df = pd.read_csv('/input/titanic_processed.csv')
titanic_df.head()

Затем мы разделим функции и целевую переменную, сохраним функции в списке FEATURES.

FEATURES = list(titanic_df.columns[1:])
FEATURES

После этого мы создадим несколько вспомогательных функций для использования этих данных и моделей SVM. Для сравнения мы сравним это с другим классификатором, известным как логистическая регрессия. Функции, которые мы напишем, этоsummate_classification, build_model, logistic_fn, linear_svc_fn, compare_results. Мы также создадим словарь для хранения метрик этих моделей. Показатели, которые мы рассматриваем, — это точность, точность и полнота.

def summarize_classification(y_test, y_pred):
    
    acc = accuracy_score(y_test, y_pred, normalize=True) #Interms of fraction(percentage)
    num_acc = accuracy_score(y_test, y_pred, normalize=False) #Interms of numbers
    
    prec = precision_score(y_test, y_pred)
    recall = recall_score(y_test, y_pred)
    
    return {'accuracy': acc,
            'precision': prec,
            'recall': recall,
            'accuracy_count': num_acc}


def build_model(classifier_fn,
               name_of_y_col,
               names_of_x_cols,
               dataset,
               test_frac=0.2):
    
    X = dataset[names_of_x_cols]
    Y = dataset[name_of_y_col]
    
    x_train,x_test,y_train,y_test = train_test_split(X,Y,test_size=test_frac)
    model = classifier_fn(x_train, y_train)
    y_pred = model.predict(x_test)
    y_pred_train = model.predict(x_train)
    
    train_summary = summarize_classification(y_train, y_pred_train)
    test_summary = summarize_classification(y_test, y_pred)
    
    pred_results = pd.DataFrame({'y_test': y_test,
                                'y_pred': y_pred})
    
    model_crosstab = pd.crosstab(pred_results.y_pred, pred_results.y_test)
    
    return { 'training': train_summary,
            'test': test_summary,
            'confusion_matrix': model_crosstab}


def compare_results():
    for key in result_dict:
        print('Classification:', key)
        
        print()
        print('Training data')
        for score in result_dict[key]['training']:
            print(score, result_dict[key]['training'][score])
            
        print()
        print('Test data')
        for score in result_dict[key]['test']:
            print(score, result_dict[key]['test'][score])
        print()


def logistic_fn(x_train, y_train):
    
    model = LogisticRegression(solver='liblinear')
    model.fit(x_train,y_train)
    
    return model


def linear_svc_fn(x_train, y_train, C=1.0, max_iter=1000, tol=1e-3):
    
    model = LinearSVC(C=C, max_iter=max_iter, tol=tol, dual=False)
    model.fit(x_train, y_train)
    
    return model

Вывод и результаты этих моделей хранятся в словаре result_dict{}.

result_dict['survived-logistic'] = build_model(logistic_fn,
                                              'Survived',
                                              FEATURES,
                                              titanic_df)

result_dict['survived - linear_svc'] = build_model(linear_svc_fn,
                                                  'Survived',
                                                  FEATURES,
                                                  titanic_df)

compare_results()

Кажется, что LogisticRegression имеет большую точность и аккуратность, но производительность SVC также можно увеличить за счет большего количества итераций.

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

Sklearn предоставил нам возможность использовать эту штрафную функцию. Если мы посмотрим на код функции linear_svc_fn, то увидим, что передается параметр «. C – обратное значение силы регуляризации. Меньшие значения указывают на более сильную регуляризацию, которая штрафует точки на неправильной стороне поля класса. Если мы назначаем очень высокий штраф за выбросы, это эквивалентно жесткой классификации маржи. Если значения C, которые мы выбрали, малы, мы лишь слегка штрафуем выбросы, это классификация с мягкой маржой.

В функции используется еще один параметр с именем "dual". Если в данных нет выборок › нет признаков, то задается параметр «dual=False», что и в нашем случае. dual=False также относится к проблеме оптимизации. Когда мы выполняем оптимизацию в машинном обучении, можно преобразовать то, что называется основной проблемой, в двойную проблему. Двойственная проблема — это та, которую легче решить с помощью оптимизации.

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