Примечание
Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере через JupyterLite или Binder.
Построение границ классификации для разных ядер SVM
В этом примере показано, как разные ядра в SVC (классификаторе опорных векторов) влияют на границы классификации в задаче бинарной классификации на плоскости.
Цель SVC — найти гиперплоскость, которая эффективно разделяет классы в обучающих данных, максимизируя зазор между крайними точками данных каждого класса. Для этого находится наилучший вектор весов \(w\), задающий гиперплоскость границы принятия решения и минимизирующий сумму потерь шарнира для ошибочно классифицированных образцов, вычисляемую с помощью функции hinge_loss. По умолчанию применяется регуляризация с параметром C=1, допускающим некоторую степень ошибок классификации.
Если данные не являются линейно разделимыми в исходном пространстве признаков, можно задать нелинейный параметр ядра. В зависимости от ядра процесс включает добавление новых признаков или преобразование существующих, чтобы обогатить данные и, возможно, придать им дополнительный смысл. Если задано ядро, отличное от "linear", SVC применяет ядерный трюк, вычисляющий сходство между парами точек данных с помощью функции ядра без явного преобразования всего набора данных. Ядерный трюк позволяет избежать необходимого в противном случае матричного преобразования всего набора данных, учитывая только отношения между всеми парами точек данных. Функция ядра сопоставляет два вектора (каждую пару наблюдений) с мерой их сходства, используя их скалярное произведение.
Затем гиперплоскость можно вычислить с помощью функции ядра так, как если бы набор данных был представлен в пространстве большей размерности. Использование функции ядра вместо явного матричного преобразования повышает производительность, поскольку временная сложность функции ядра составляет \(O({n}^2)\), тогда как сложность матричного преобразования зависит от конкретного применяемого преобразования.
В этом примере мы сравним наиболее распространённые типы ядер машин опорных векторов: линейное ядро ("linear"), полиномиальное ядро ("poly"), ядро радиальной базисной функции ("rbf") и сигмоидальное ядро ("sigmoid").
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Создание набора данных
Мы создадим двумерный набор данных для классификации из 16 образцов и двух классов. Отобразим образцы, раскрасив их в соответствии с целевыми значениями.
import matplotlib.pyplot as plt
import numpy as np
X = np.array(
[
[0.4, -0.7],
[-1.5, -1.0],
[-1.4, -0.9],
[-1.3, -1.2],
[-1.1, -0.2],
[-1.2, -0.4],
[-0.5, 1.2],
[-1.5, 2.1],
[1.0, 1.0],
[1.3, 0.8],
[1.2, 0.5],
[0.2, -2.0],
[0.5, -2.4],
[0.2, -2.3],
[0.0, -2.7],
[1.3, 2.1],
]
)
y = np.array([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1])
# Plotting settings
fig, ax = plt.subplots(figsize=(4, 3))
x_min, x_max, y_min, y_max = -3, 3, -3, 3
ax.set(xlim=(x_min, x_max), ylim=(y_min, y_max))
# Plot samples by color and add legend
scatter = ax.scatter(X[:, 0], X[:, 1], s=150, c=y, label=y, edgecolors="k")
ax.legend(*scatter.legend_elements(), loc="upper right", title="Classes")
ax.set_title("Samples in two-dimensional feature space")
plt.show()

Видно, что образцы нельзя чётко разделить прямой линией.
Обучение модели SVC и построение границ принятия решения
Определим функцию, которая обучает классификатор SVC, принимает параметр kernel и строит границы принятия решения, выученные моделью, с помощью DecisionBoundaryDisplay.
Обратите внимание, что для простоты в этом примере параметр C задан значением по умолчанию (C=1), а параметр gamma установлен в gamma=2 для всех ядер, хотя для линейного ядра он автоматически игнорируется. В реальной задаче классификации, где важна производительность, настоятельно рекомендуется подбирать параметры (например, с помощью GridSearchCV), чтобы учитывать различные структуры данных.
Задание response_method="predict" в DecisionBoundaryDisplay окрашивает области в зависимости от предсказанного для них класса. Параметр response_method="decision_function" позволяет также построить границу принятия решения и отступы по обе стороны от неё. Наконец, опорные векторы, использованные при обучении (которые всегда находятся на границах отступов), определяются с помощью атрибута support_vectors_ обученных SVC и также отображаются на графике.
from sklearn import svm
from sklearn.inspection import DecisionBoundaryDisplay
def plot_training_data_with_decision_boundary(
kernel, ax=None, long_title=True, support_vectors=True
):
# Train the SVC
clf = svm.SVC(kernel=kernel, gamma=2).fit(X, y)
# Settings for plotting
if ax is None:
_, ax = plt.subplots(figsize=(4, 3))
x_min, x_max, y_min, y_max = -3, 3, -3, 3
ax.set(xlim=(x_min, x_max), ylim=(y_min, y_max))
# Plot decision boundary and margins
common_params = {"estimator": clf, "X": X, "ax": ax}
DecisionBoundaryDisplay.from_estimator(
**common_params,
response_method="predict",
plot_method="pcolormesh",
alpha=0.3,
)
DecisionBoundaryDisplay.from_estimator(
**common_params,
response_method="decision_function",
plot_method="contour",
levels=[-1, 0, 1],
colors=["k", "k", "k"],
linestyles=["--", "-", "--"],
)
if support_vectors:
# Plot bigger circles around samples that serve as support vectors
ax.scatter(
clf.support_vectors_[:, 0],
clf.support_vectors_[:, 1],
s=150,
facecolors="none",
edgecolors="k",
)
# Plot samples by color and add legend
ax.scatter(X[:, 0], X[:, 1], c=y, s=30, edgecolors="k")
ax.legend(*scatter.legend_elements(), loc="upper right", title="Classes")
if long_title:
ax.set_title(f" Decision boundaries of {kernel} kernel in SVC")
else:
ax.set_title(kernel)
if ax is None:
plt.show()
Линейное ядро
Линейное ядро — это скалярное произведение входных образцов:
Затем оно применяется к любым двум точкам данных (образцам) из набора данных. Скалярное произведение двух точек определяет меру cosine_similarity между ними. Чем выше значение, тем больше сходство между точками.
plot_training_data_with_decision_boundary("linear")

Обучение SVC с линейным ядром выполняется в непреобразованном пространстве признаков, где гиперплоскость и отступы представляют собой прямые линии. Из-за ограниченной выразительности линейного ядра обученные классы не идеально соответствуют обучающим данным.
Полиномиальное ядро
Полиномиальное ядро изменяет понятие сходства. Функция ядра определяется следующим образом:
где \({d}\) — степень полинома (degree), \({\gamma}\) (gamma) определяет влияние каждого отдельного обучающего образца на границу принятия решения, а \({r}\) — свободный член (coef0), смещающий данные вверх или вниз. Здесь мы используем значение степени полинома в функции ядра по умолчанию (degree=3). Если coef0=0 (значение по умолчанию), данные только преобразуются, но дополнительное измерение не добавляется. Использование полиномиального ядра эквивалентно созданию PolynomialFeatures с последующим обучением SVC с линейным ядром на преобразованных данных, хотя такой альтернативный подход был бы вычислительно затратным для большинства наборов данных.
plot_training_data_with_decision_boundary("poly")

Полиномиальное ядро с gamma=2 хорошо подстраивается под обучающие данные, из-за чего отступы по обе стороны гиперплоскости соответственно изгибаются.
Ядро RBF
Ядро радиальной базисной функции (RBF), также известное как гауссово ядро, является ядром по умолчанию для машин опорных векторов в scikit-learn. Оно измеряет сходство двух точек данных в пространстве бесконечной размерности, а затем выполняет классификацию методом голосования большинством. Функция ядра определяется следующим образом:
где \({\gamma}\) (gamma) определяет влияние каждого отдельного обучающего образца на границу принятия решения.
Чем больше евклидово расстояние между двумя точками \(\|\mathbf{x}_1 - \mathbf{x}_2\|^2\), тем ближе значение функции ядра к нулю. Это означает, что точки, расположенные далеко друг от друга, с большей вероятностью будут непохожи.
plot_training_data_with_decision_boundary("rbf")

На графике видно, что границы принятия решения стремятся стягиваться вокруг близко расположенных друг к другу точек данных.
Сигмоидальное ядро
Функция сигмоидального ядра определяется следующим образом:
где коэффициент ядра \({\gamma}\) (gamma) определяет влияние каждого отдельного обучающего образца на границу принятия решения, а \({r}\) — свободный член (coef0), смещающий данные вверх или вниз.
В сигмоидальном ядре сходство двух точек данных вычисляется с помощью гиперболического тангенса (\(\tanh\)). Функция ядра масштабирует и, возможно, смещает скалярное произведение двух точек (\(\mathbf{x}_1\) и \(\mathbf{x}_2\)).
plot_training_data_with_decision_boundary("sigmoid")

Видно, что границы принятия решения, полученные с помощью сигмоидального ядра, выглядят изогнутыми и неровными. Граница пытается разделить классы, подстраиваясь под кривую сигмоидальной формы, что приводит к сложной границе, которая может плохо обобщаться на новые данные. Этот пример показывает, что сигмоидальное ядро имеет очень специфические области применения — например, для данных с сигмоидальной формой. В данном примере тщательная настройка параметров может помочь найти границы принятия решения, лучше обобщающиеся на новые данные. Из-за узкой области применения сигмоидальное ядро используется на практике реже, чем другие ядра.
Заключение
В этом примере мы визуализировали границы принятия решения, обученные на предоставленном наборе данных. Графики наглядно демонстрируют, как разные ядра используют обучающие данные для определения границ классификации.
Гиперплоскости и отступы, хотя и вычисляются косвенно, можно представить в виде плоскостей в преобразованном пространстве признаков. Однако на графиках они показаны относительно исходного пространства признаков, поэтому границы принятия решения для полиномиального ядра, RBF и сигмоидального ядра выглядят кривыми.
Обратите внимание, что графики не оценивают точность или качество отдельных ядер. Они предназначены для наглядного представления того, как разные ядра используют обучающие данные.
Для всесторонней оценки рекомендуется тщательно подбирать параметры SVC с помощью таких методов, как GridSearchCV, чтобы учитывать лежащие в основе данных структуры.
Набор данных XOR
Классический пример набора данных, который нельзя разделить линейно, — это структура XOR. Здесь мы покажем, как разные ядра работают на таком наборе данных.
xx, yy = np.meshgrid(np.linspace(-3, 3, 500), np.linspace(-3, 3, 500))
np.random.seed(0)
X = np.random.randn(300, 2)
y = np.logical_xor(X[:, 0] > 0, X[:, 1] > 0)
_, ax = plt.subplots(2, 2, figsize=(8, 8))
args = dict(long_title=False, support_vectors=False)
plot_training_data_with_decision_boundary("linear", ax[0, 0], **args)
plot_training_data_with_decision_boundary("poly", ax[0, 1], **args)
plot_training_data_with_decision_boundary("rbf", ax[1, 0], **args)
plot_training_data_with_decision_boundary("sigmoid", ax[1, 1], **args)
plt.show()

Как видно на графиках выше, только ядро rbf позволяет найти подходящую границу принятия решения для этого набора данных.
Общее время выполнения скрипта: (0 минут 1.656 секунды)
Похожие примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/svm/plot_svm_kernels.html