Используйте matplotlib для визуализации границ решений для алгоритмов классификации в Python
Введение
В последнее время я некоторое время пытался визуализировать сгенерированную модель модели классификации. Я полагался только на отчет о классификации и матрицу неточностей, чтобы оценить характеристики модели.
Однако визуализация результатов классификации имеет свое очарование и делает ее более понятной. Итак, я построил поверхность для принятия решений, и когда мне это удалось, я решил написать об этом как о процессе обучения и для всех, кто, возможно, застрял на той же проблеме.
Содержание учебного пособия
В этом руководстве я начну со встроенного пакета набора данных в библиотеке Sklearn, чтобы сосредоточиться на этапах реализации. После этого я буду использовать предварительно обработанные данные (без пропущенных данных или выбросов) для построения поверхности принятия решений после применения стандартного средства масштабирования.
- Поверхность принятия решения
- Импорт важных библиотек
- Генерация набора данных
- Создание поверхности принятия решений
- Подача заявки на получение реальных данных
Поверхность принятия решения
Классификация в машинном обучении означает обучение ваших данных назначению меток для примеров ввода.
Каждый входной объект определяет ось в пространстве признаков. Плоскость характеризуется как минимум двумя входными элементами, с точками, представляющими входные координаты во входном пространстве. Если бы было три входные переменные, пространство признаков было бы трехмерным объемом.
Конечная цель классификации - разделить пространство объектов так, чтобы метки назначались точкам в пространстве объектов как можно точнее.
Этот метод называется поверхностью решения или границей решения, и он работает как демонстрационный инструмент для объяснения модели в задаче прогнозного моделирования классификации. Мы можем создать поверхность принятия решений для каждой пары входных функций, если у вас более двух входных функций.
Импорт важных библиотек
import numpy as np import pandas as pd import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap from sklearn import datasets from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.metrics import accuracy_score, confusion_matrix from sklearn.model_selection import train_test_split
Создать набор данных
Я буду использовать функцию make_blobs()
в классе наборов данных из библиотеки Sklearn для создания настраиваемого набора данных. Это позволит сосредоточиться на реализации, а не на очистке данных. Однако шаги те же и представляют собой типичный шаблон.
Для простоты давайте начнем с определения переменных набора данных с 1000 выборками и только двумя функциями и стандартным отклонением 3.
X, y = datasets.make_blobs(n_samples = 1000, centers = 2, n_features = 2, random_state = 1, cluster_std = 3)
После создания набора данных мы можем построить диаграмму рассеяния, чтобы увидеть изменчивость между переменными.
# create scatter plot for samples from each class for class_value in range(2): # get row indexes for samples with this class row_ix = np.where(y == class_value) # create scatter of these samples plt.scatter(X[row_ix, 0], X[row_ix, 1]) # show the plot plt.show()
Здесь мы перебрали набор данных и нанесли точки между каждым X
и y
, окрашенные меткой класса. На следующем этапе нам нужно построить модель прогнозной классификации, чтобы предсказать класс невидимых точек. В этом случае можно использовать логистическую регрессию, поскольку у нас есть только две категории.
Разработайте модель логистической регрессии
regressor = LogisticRegression() # fit the regressor into X and y regressor.fit(X, y) # apply the predict method y_pred = regressor.predict(X)
Все y_pred
можно оценить с помощью accuracy_score
class из библиотекиsklearn
.
accuracy = accuracy_score(y, y_pred) print('Accuracy: %.3f' % accuracy) ## Accuracy: 0.972
Создание поверхности принятия решений
matplotlib
предоставляет удобную функцию contour()
, которая может вставлять цвета между точками. Однако, как предлагается в документации, нам необходимо определить сетку точек X
из y
в пространстве функций. Отправной точкой было бы найти максимальное значение и минимальное значение каждой функции, а затем увеличить их на единицу, чтобы убедиться, что все пространство покрыто.
min1, max1 = X[:, 0].min() - 1, X[:, 0].max() + 1 #1st feature min2, max2 = X[:, 1].min() - 1, X[:, 1].max() + 1 #2nd feature
Затем мы можем определить масштаб координат, используя функцию arange()
из библиотеки numpy
с разрешением0.01
, чтобы получить диапазон масштаба.
x1_scale = np.arange(min1, max1, 0.1) x2_scale = np.arange(min2, max2, 0.1)
Следующим шагом будет преобразование x1_scale
и x2_scale
в сетку. Функция meshgrid()
из библиотеки numpy
- это то, что нам нужно.
x_grid, y_grid = np.meshgrid(x1_scale, x2_scale)
Сгенерированный x_grid
представляет собой двумерный массив. Чтобы использовать его, нам нужно уменьшить размер до одномерного массива, используя метод flatten()
из библиотекиnumpy
.
# flatten each grid to a vector x_g, y_g = x_grid.flatten(), y_grid.flatten() x_g, y_g = x_g.reshape((len(x_g), 1)), y_g.reshape((len(y_g), 1))
Наконец, складываем векторы бок о бок в виде столбцов во входном наборе данных, как в исходном наборе данных, но с гораздо более высоким разрешением.
grid = np.hstack((x_g, y_g))
Теперь мы можем вписаться в модель, чтобы предсказывать значения.
# make predictions for the grid y_pred_2 = model.predict(grid) #predict the probability p_pred = model.predict_proba(grid) # keep just the probabilities for class 0 p_pred = p_pred[:, 0] # reshaping the results p_pred.shape pp_grid = p_pred.reshape(x_grid.shape)
Теперь сгенерирована сетка значений и метка прогнозируемого класса по пространству функций.
Впоследствии мы построим эти сетки как контурный график, используя contourf()
.
Для функции contourf()
требуются отдельные сетки для каждой оси. Для этого мы можем использовать x_grid
и y_grid
и изменить форму прогнозов (y_pred)
, чтобы они имели ту же форму.
# plot the grid of x, y and z values as a surface surface = plt.contourf(x_grid, y_grid, pp_grid, cmap='Pastel1') plt.colorbar(surface) # create scatter plot for samples from each class for class_value in range(2): # get row indexes for samples with this class row_ix = np.where(y == class_value) # create scatter of these samples plt.scatter(X[row_ix, 0], X[row_ix, 1], cmap='Pastel1') # show the plot plt.show()
Применить к реальным данным
Теперь пора применить предыдущие шаги к реальным данным, чтобы все связать. Как я упоминал ранее, этот набор данных уже очищен без пропущенных точек. Набор данных представляет собой историю покупок автомобилей для выборки людей в соответствии с их возрастом и зарплатой в год.
dataset = pd.read_csv('../input/logistic-reg-visual/Social_Network_Ads.csv') dataset.head()
В наборе данных есть две функции Age
и EstimatedSalary
и одна зависимая переменная, приобретенная как двоичный столбец. Значение 0 представляет человека с таким же возрастом и зарплатой, который не покупал машину. Однако одно означает, что человек действительно купил машину. Следующим шагом будет отделение зависимой переменной от таких функций, как X и y.
X = dataset.iloc[:, :-1].values y = dataset.iloc[:, -1].values # splitting the dataset X_train, X_test, y_train, y_test = train_test_split( X, y, test_size = 0.25, random_state = 0)
Масштабирование функций
Нам нужен этот шаг, потому что Age
и salary
не в одном масштабе
sc = StandardScaler() X_train = sc.fit_transform(X_train) X_test = sc.transform(X_test)
Построение логистической модели и соответствие обучающим данным
classifier = LogisticRegression(random_state = 0) # fit the classifier into train data classifier.fit(X_train, y_train) # predicting the value of y y_pred = classifier.predict(X_test)
Постройте поверхность решения - результаты обучения
#1. reverse the standard scaler on the X_train
X_set, y_set = sc.inverse_transform(X_train), y_train
#2. Generate decision surface boundaries
min1, max1 = X_set[:, 0].min() - 10, X_set[:, 0].max() + 10 # for Age
min2, max2 = X_set[:, 1].min() - 1000, X_set[:, 1].max() + 1000 # for salary
#3. Set coordinates scale accuracy
x_scale ,y_scale = np.arange(min1, max1, 0.25), np.arange(min2, max2, 0.25)
#4. Convert into vector
X1, X2 = np.meshgrid(x_scale, y_scale)
#5. Flatten X1 and X2 and return the output as a numpy array
X_flatten = np.array([X1.ravel(), X2.ravel()])
#6. Transfor the results into it's original form before scaling
X_transformed = sc.transform(X_flatten.T)
#7. Generate the prediction and reshape it to the X to have the same shape
Z_pred = classifier.predict(X_transformed).reshape(X1.shape)
#8. set the plot size
plt.figure(figsize=(20,10))
#9. plot the contour function
plt.contourf(X1, X2, Z_pred,
alpha = 0.75,
cmap = ListedColormap(('#386cb0', '#f0027f'
)))
#10. setting the axes limit
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
#11. plot the points scatter plot ( [salary, age] vs. predicted classification based on training set)
for i, j in enumerate(np.unique(y_set)):
plt.scatter(X_set[y_set == j, 0],
X_set[y_set == j, 1],
c = ListedColormap(('red', 'green'))(i),
label = j)
#12. plot labels and adjustments
plt.title('Logistic Regression (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
График решения для тестового набора
Он точно такой же, как и предыдущий код, но вместо использования тестового набора поездов.
Вывод
Наконец, я надеюсь, что этот шаблон может помочь в визуализации результатов модели классификации. Я рекомендую применить те же шаги, используя другую модель классификации, например, SVM с более чем двумя функциями.
Спасибо за чтение, жду любых конструктивных комментариев.