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

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

  1. Импортировать необходимые библиотеки
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

2. Загрузите набор данных make_circles из sklearn.

from sklearn.datasets import make_circles
n_samples = 1000
X,y = make_circles(n_samples,
                   noise = 0.03,
                   random_state=42)

3. Проверьте форму X и Y

X.shape, y.shape
-> ((1000, 2), (1000,))

4. Образец точки и метка

X[4], y[4] 
-> (array([ 0.44220765, -0.89672343]), 0)

5 . Преобразуйте данные в кадр данных pandas и проверьте первые несколько строк.

circles = pd.DataFrame({"X0":X[:,0], "X1":X[:,1], "label":y})
circles.head()

6. Нанесите данные

plt.scatter(X[:,0],X[:,1], c = y, cmap =plt.cm.RdYlBu);

X[:,0] обозначает все строки и первый столбец массива X,

X[:,1] обозначает все строки и второй столбец для массива X,

c = y означает, что цвет точек X на графике будет соответствовать их меткам y. Таким образом, на приведенном ниже графике все точки с меткой 1 окрашены в красный цвет, а все точки с меткой 0 — в синий.

7. Разделите данные на обучающие и тестовые наборы в соотношении 80:20.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
-> ((800, 2), (200, 2), (800,), (200,))

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

import tensorflow as tf
model = tf.keras.Sequential([
          tf.keras.layers.Dense(20,activation='relu'),
          tf.keras.layers.Dense(1, activation = 'sigmoid')
])
model.compile(loss = tf.keras.losses.BinaryCrossentropy(),
                optimizer = tf.keras.optimizers.Adam(),                        metrics = ['accuracy']
)
model.fit(X_train, y_train, epochs=100)

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

Граничные шаги решения

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

9. Найдите минимальные и максимальные координаты x и y для наших данных

x_min, x_max = X[:, 0].min() - 0.1, X[:,0].max() + 0.1
y_min, y_max = X[:, 1].min() - 0.1, X[:, 1].max() + 0.1

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

10. Используя указанные выше границы, мы создадим прямоугольную сетку точек внутри этих границ, используя метод meshgrid NumPy. Эта сетка поможет в построении контура/формы границы нашего решения.

xx, yy = np.meshgrid(np.linspace(x_min,x_max, 100),
np.linspace(y_min, y_max, 100))

мы берем экстремальные значения и создаем 100 равноудаленных точек в обоих направлениях x и y и объединяем их, чтобы создать координаты x и y каждой точки в сетке сетки, которая будет выглядеть примерно так:

11. Теперь нам нужно получить предсказанные значения для каждой из точек сетки. Для этого нам нужно соединить координаты xx и yy, полученные выше, по секунде (ось =1). Для этого мы используем метод NumPy c_:

x_in = np.c_[xx.ravel(), yy.ravel()]

Метод np.ravel сводит массивы xx и yy в одномерный массив.

12. Получите прогнозируемые значения, используя нашу обученную модель сверху.

y_pred = model_1.predict(x_in)

13. Нам нужно изменить форму y_pred, чтобы она была той же формы, что и xx, для использования в функции контура.

y_pred = np.round(y_pred).reshape(xx.shape)

14. Теперь мы готовы построить нашу границу решения. Для этого мы можем использовать функцию контура matplotlib вместе с точечной диаграммой для построения исходных данных.

plt.contourf(xx, yy, y_pred, cmap=plt.cm.RdYlBu, alpha=0.7 )
plt.scatter(X[:,0], X[:, 1], c=y, s=40, cmap=plt.cm.RdYlBu)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())

Получаем следующий рисунок:

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

Спасибо за прочтение.