Анализируемый датасет содержит размеченные сведения о том, купил ли товар определенный пользователь или нет. О пользователе известны такие данные как: возраст, пол и ориентировочная зарплата. О покупках данные представлены в виде: 1 - покупка совершена, 0 - нет. В данной статье попробуем обучить модель, прогнозирующую вероятность соверешения покупки, если нам известны данные о пользователе. Будут применены методы: метод ближайшего соседа (KNN, K nearest neighbor), метод опорных векторов (SVM, support vector machines) и ядра SVM (Kernal SVM) с подбором оптимальных гиперпараметров для модели.
1. Импортирование нужных библиотек и загрузка данных из датасета
4. Кодирование категориальных данных
5. Разделение датасета на тренировочный и тестовый блоки
6. Нормализация данных (масштабирование признаков (фич))
7. Метод K-ближайших соседей (K Nearest Neighbor(KNN)
# библиотека линейной алгебры
import numpy as np
# библиотека обработки данных
import pandas as pd
# библиотеки для визуализации
import seaborn as sns
import matplotlib.pyplot as plt
# библиотека обработки фич
from sklearn.preprocessing import StandardScaler
# библиотека для разделения данных на тренировочные и тестовые
from sklearn.model_selection import train_test_split
# библиотеки для классификации в моделях
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
# библиотека настройки гиперпараметров
from sklearn.model_selection import GridSearchCV
# библиотеки оценивания\метрики
from sklearn.metrics import confusion_matrix, accuracy_score, classification_report,recall_score,precision_score
            # библиотека для "раскраски" таблиц.
import jinja2
# если модуль не установлен, то выполнить команду ниже
# !pip install Jinja2
            Загрузка данных из csv-файла.
df = pd.read_csv('data.csv')
            # Смотрим размер таблицы.
print("Количество строк = ", df.shape[0], " \nКоличество столбцов = " , df.shape[1]) 
            Количество строк = 400 Количество столбцов = 5
# Смотрим список столбцов.
df.columns
            Index(['ID', 'Пол', 'Возраст', 'Зарплата', 'Покупка'], dtype='object')
# Смотрим информацию о столбцах и выводим несколько случайных строк с данными.
print(df.info())
            <class 'pandas.core.frame.DataFrame'> RangeIndex: 400 entries, 0 to 399 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Возраст 400 non-null int8 1 Зарплата 400 non-null int32 2 Покупка 400 non-null int8 3 Пол_м 400 non-null uint8 dtypes: int32(1), int8(2), uint8(1) memory usage: 2.9 KB None
Видим, что числовые столбцы определились неоптимальным типом (int64), поэтому при больших данных можно применить функцию оптимизации из этой статьи.
# Выводим несколько случайных строк с данными.
# Цвета "расскраски" см. тут https://matplotlib.org/stable/tutorials/colors/colormaps.html
# "расскраска" по столбцам
df.sample(10).style.background_gradient(axis=0, cmap='Spectral')
            | Возраст | Зарплата | Покупка | Пол_м | |
|---|---|---|---|---|
| 171 | 41 | 60000 | 0 | 0 | 
| 42 | 22 | 27000 | 0 | 0 | 
| 107 | 45 | 45000 | 1 | 0 | 
| 62 | 45 | 32000 | 1 | 1 | 
| 47 | 33 | 28000 | 0 | 0 | 
| 362 | 36 | 125000 | 1 | 1 | 
| 377 | 32 | 135000 | 1 | 0 | 
| 9 | 22 | 18000 | 0 | 1 | 
| 76 | 20 | 36000 | 0 | 0 | 
| 13 | 19 | 19000 | 0 | 1 | 
Все поля числовые, кроме пола (имеем одну категорию Пол).
# анализируем основные показатели по числовым столбцам
# "расскраска" по строкам
df.describe().T.style.background_gradient(axis=1, cmap='Spectral')
            | count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| ID | 400.000000 | 5058.500000 | 115.614301 | 4859.000000 | 4958.750000 | 5058.500000 | 5158.250000 | 5258.000000 | 
| Возраст | 400.000000 | 37.655000 | 10.482877 | 18.000000 | 29.750000 | 37.000000 | 46.000000 | 60.000000 | 
| Зарплата | 400.000000 | 69742.500000 | 34096.960282 | 15000.000000 | 43000.000000 | 70000.000000 | 88000.000000 | 150000.000000 | 
| Покупка | 400.000000 | 0.357500 | 0.479864 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 
# проверяем на наличие дубликатов.
df.duplicated().sum()
            0
# Анализ на пропущенные значения
df.isnull().sum()
            ID 0 Пол 0 Возраст 0 Зарплата 0 Покупка 0 dtype: int64
В данном датасете нет пропущенных значений.
# Тепловая карта (heatmap)
plt.figure(figsize=(10, 5))
mask = np.triu(np.ones_like(df.corr(), dtype=bool))
sns.heatmap(df.corr(), mask = mask, annot=True, cmap='Spectral');
            correlation = pd.DataFrame(df.corr().Покупка)
correlation
            | Покупка | |
|---|---|
| ID | 0.614944 | 
| Возраст | 0.622454 | 
| Зарплата | 0.362083 | 
| Покупка | 1.000000 | 
Колонка с идентификатором пользователя уникальная для всех, поэтому не может участвовать в прогнозе и может быть удалена.
df.drop('ID', axis = 1, inplace=True)
            mask = np.triu(np.ones_like(df.corr(), dtype=bool))
sns.heatmap(df.corr(), mask = mask, annot=True, cmap='Spectral');
            # Смотрим количество покупок и "не покупок"
df['Покупка'].value_counts()
            0 257 1 143 Name: Покупка, dtype: int64
# в виде гистограммы
plt.figure(figsize=(10, 3))
sns.countplot(x = "Покупка", data=df, palette="Spectral")
plt.show()
            Визуализация и анализ цели в зависимости от пола
plt.figure(figsize=(10, 3))
sns.catplot(x='Покупка', col='Пол', kind='count', data=df,palette="Spectral");
plt.show()
            <Figure size 720x216 with 0 Axes>
pd.crosstab(df.Пол, df.Покупка, normalize = "index" ).style.background_gradient(cmap='Spectral')
            | Покупка | 0 | 1 | 
|---|---|---|
| Пол | ||
| ж | 0.622549 | 0.377451 | 
| м | 0.663265 | 0.336735 | 
На данном примере видно соотношение женщин и мужчик совершивших покупки (целевой критерий).
Распределение и визуализация значений возраста и ориентировочной зарплаты
# анализ распределения возраста
sns.histplot(df['Возраст'], kde=True, color='green', bins=30)
            <AxesSubplot:xlabel='Возраст', ylabel='Count'>
# анализ распределения зарплаты
sns.histplot(df['Зарплата'], kde=True, color='blue', bins=30)
            <AxesSubplot:xlabel='Зарплата', ylabel='Count'>
Смещение в сторону возрастной группы 35-40 лет, а по заработной плате - от 70 до 90 тысяч
Парный график возраста и зарплаты в соотнесении с целевым критерием (покупкой)
sns.pairplot(df , hue = 'Покупка', palette='Spectral', corner=True )
            <seaborn.axisgrid.PairGrid at 0x146bce1a100>
Диаграмма разброса возраста и заработной платы по отношению к цели
sns.scatterplot(x = 'Возраст', y = 'Зарплата', data = df, hue = 'Покупка', palette ='Spectral')
            <AxesSubplot:xlabel='Возраст', ylabel='Зарплата'>
Из парного графика и диаграммы разброса видно, что если масштабирование не выполняется, зарплата будет преобладать над возрастом, что приведет к смещению модели. Масштабирование фич будет выполнено после разделения модели на тренировочный и тестовый наборы.
Колонка Пол содержит категориальные значения, поэтому ее необходимо закодировать в числовые значения до построения модели.
При кодировании категориальных данных для каждого различного значения будет создана фиктивная числовая переменная для указанных колонок. Для этого применяем функцию pandas.get_dummies(), которая возвращает преобразованные данные, а также удаляет исходные (в зависимости от значения параметра drop_first).
df = pd.get_dummies(df, columns = ['Пол'], drop_first=True)
            df.head()
            | Возраст | Зарплата | Покупка | Пол_м | |
|---|---|---|---|---|
| 0 | 26 | 15000 | 0 | 1 | 
| 1 | 26 | 15000 | 0 | 0 | 
| 2 | 30 | 15000 | 0 | 1 | 
| 3 | 31 | 15000 | 0 | 0 | 
| 4 | 21 | 16000 | 0 | 0 | 
Сохраняем отдельно целевые значения и отдельные данные без целевых значений.
X = df.drop(['Покупка'], axis = 1)
y = df['Покупка']
            # разделение данных
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
            X_train.shape
            (300, 3)
Масштабирование признаков (фич) - это приведение всех значений всех признаков к "схожему масштабу". Это предотвращает преобладание одного признака над другим. В данном примере без масштабирования зарплата преобладает над возрастом.
Эта процедура делается после разделения датасета на тренировочный и тестовый наборы и применяется к тренировочному набору.
Для масштабирования признаков используем метод fit_transform() для тренировочных данных и метод transform() для тестовых.
fit_transform() : - применяется только к тренировочному набору данных. Он содержит два метода: fit() и transform(). Fit() произведет необходимые математические вычисления и получит средние значения и стандартные отклонение на базе входных данных. Это делается на тренировочных данных для того, чтобы модель не знала значения из тестового набора, т.к. предполагается, что тестовые данные - это как бы реальные данные для проверки работы модели. Метод transform() применит вычисленные значения к набору данных или преобразует данные в соответствии с моделью.
transform() :- Метод transform() применяется к тестовому набору данных, и тестовые данные трансформируются или масштабируются при помощи параметров модели, обученной на применении соответствующего метода на тренировочном датасете.
cols = X_train.columns
cols
            Index(['Возраст', 'Зарплата', 'Пол_м'], dtype='object')
# Выполнение стандартизации при помощи sklearn.preprocessing.StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
            X_train
            array([[ 0.18361861,  0.2184173 ,  1.05483461],
       [ 0.7564323 , -1.14483856, -0.94801592],
       ...
       [ 0.85190124, -0.64102661, -0.94801592],
       [-0.48466403, -1.26338255, -0.94801592],
       [ 1.71112178, -0.31503065,  1.05483461]])
          X_test
            array([[ 0.27908756, -0.55211862,  1.05483461],
       [-0.77107087,  0.54441326,  1.05483461],
       [ 2.09299757,  1.1074972 , -0.94801592],
       ....
       [ 0.85190124,  2.17439309, -0.94801592],
       [-0.86653982,  0.27768929,  1.05483461],
       [-0.19825718,  1.64094515, -0.94801592]])
          # Создание датасетов на базе полученных данных.
X_train = pd.DataFrame(X_train,columns=cols)
X_test = pd.DataFrame(X_test,columns=cols)
            # результат нормализации даных.
X_train
            | Возраст | Зарплата | Пол_м | |
|---|---|---|---|
| 0 | 0.183619 | 0.218417 | 1.054835 | 
| 1 | 0.756432 | -1.144839 | -0.948016 | 
| 2 | -1.248416 | 0.574049 | 1.054835 | 
| 3 | -0.962009 | -0.344667 | 1.054835 | 
| 4 | 2.092998 | 0.366597 | 1.054835 | 
| ... | ... | ... | ... | 
| 295 | 0.947370 | 0.751865 | -0.948016 | 
| 296 | 1.042839 | -0.166851 | 1.054835 | 
| 297 | 0.851901 | -0.641027 | -0.948016 | 
| 298 | -0.484664 | -1.263383 | -0.948016 | 
| 299 | 1.711122 | -0.315031 | 1.054835 | 
300 rows × 3 columns
X_test
            | Возраст | Зарплата | Пол_м | |
|---|---|---|---|
| 0 | 0.279088 | -0.552119 | 1.054835 | 
| 1 | -0.771071 | 0.544413 | 1.054835 | 
| 2 | 2.092998 | 1.107497 | -0.948016 | 
| 3 | -1.630291 | -0.077943 | -0.948016 | 
| 4 | -0.293726 | 0.188781 | -0.948016 | 
| ... | ... | ... | ... | 
| 95 | -0.102788 | -0.463211 | 1.054835 | 
| 96 | -0.102788 | -0.522483 | 1.054835 | 
| 97 | 0.851901 | 2.174393 | -0.948016 | 
| 98 | -0.866540 | 0.277689 | 1.054835 | 
| 99 | -0.198257 | 1.640945 | -0.948016 | 
100 rows × 3 columns
# просмотр распределения возраста на базе нормализованных данных
sns.histplot(X_train['Возраст'], kde=True, color='green', bins=30)
            <AxesSubplot:xlabel='Возраст', ylabel='Count'>
# просмотр распределения зарплаты на базе нормализованных данных
sns.histplot(X_train['Зарплата'], kde=True, color='blue', bins=30)
            <AxesSubplot:xlabel='Зарплата', ylabel='Count'>
K Nearest Neighbour (KNN) - это алгоритм "обучения с учителем" использующихся в осноном для зада классификации или регрессии. Он наиболее эффективен для зада классификации, в которых алгоритм определяет к какому классификационному признаку отнести исходную точку путем определения K-ближайщих точек. KNN классифицирует точку данных, базируясь на известной классификации других точек (на базе тренировочных данных).
KNN простой алгоритм, работающий на базе пространственной близости/расстояния и не нуждается в построении модели, поскольку он настраивает несколько параметров и делает предположения. KNN универсален, но становится медленнее по мере увеличения признаков (фич).
# Создание классификатора
classifierKNN = KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)
# Обучение классификатора на тренировочных данных
classifierKNN.fit(X_train.values, y_train.values)
            KNeighborsClassifier()
Метрика minkowski здесь означает MinkowskiDistance, которая рассчитывается по формуле как сумма ( | x - y | ^ p) ^( 1/p )
# Применение классификации к тестовым данным.
y_pred = classifierKNN.predict(X_test.values)
# Результат предсказания покупок на тестовых данных.
y_pred
            array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
       0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1,
       0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1,
       1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1], dtype=int8)
          y_test.values
            array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
       0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1,
       1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1], dtype=int8)
          # Оценка результатов KNN классификации
# Смотрим матрицу ошибок.
cm1 = confusion_matrix(y_test,y_pred)
print(cm1)
            [[63 5] [ 2 30]]
# Она же, но графически.
sns.heatmap(cm1, annot=True, fmt='d', cmap='Spectral')
plt.show()
            Из 100 значений предсказаний, только 7 ошибочных.
Отчет о классификации
print(classification_report(y_test, y_pred))
                          precision    recall  f1-score   support
           0       0.97      0.93      0.95        68
           1       0.86      0.94      0.90        32
    accuracy                           0.93       100
   macro avg       0.91      0.93      0.92       100
weighted avg       0.93      0.93      0.93       100
          Общая точность (accuracy) составляет 93%, а точность (precision), полнота (recall) и F1-мера для предсказания "не покупок" выше 94%, а для проноза покупок близка к 90%.
# значение ошибки.
np.mean(y_pred != y_test)
            0.07
В методе KNN выбор значения k очень важен. При маленьком значении k "шум" будет оказывать сильное воздействие на итоговый результат. Большое значение делает его затратным с точки зрения вычислений и противоречит основной идее KNN, что близкие точки могут иметь схожие плотности или классы. Значение по умолчанию для количества k-соседей - 5.
Далее в цикле пробуем применить значения k от 1 до 40 с записью значения ошибки в массив, в дальнейшем с построением графика по списку ошибок для определения оптимального значения k.
error_rate = []
for i in range(1,40):
    # создание KNN классификатора с заданным значением k
    knn = KNeighborsClassifier(n_neighbors = i)
    # обучение его на тренировочных данных
    knn.fit(X_train.values, y_train.values)
    # прогноз покупок на тестовых данных
    pred_i = knn.predict(X_test.values)
    # сохранение значения ошибки
    error_rate.append(np.mean(pred_i != y_test))
            # графическое представление процента ошибок
plt.figure(figsize=(10,6))
plt.plot(range(1,40), error_rate, color='red', linestyle='dashed', marker='o', markerfacecolor='yellow', markersize=6)
plt.title('Процент ошибок в зависимости от значения K')
plt.xlabel('K')
plt.ylabel('Процент ошибок')
            Text(0, 0.5, 'Процент ошибок')
Из графика видно, допустимый уровень ошибок при K от 5 до 18, а при значении K выше 35 уровень ошибок максимальный.
# анализ результатов при значении K = 10
knn10 = KNeighborsClassifier(n_neighbors = 10)
knn10.fit(X_train.values,y_train.values)
pred10 = knn10.predict(X_test.values)
print('При K=10')
print(confusion_matrix(y_test, pred10))
sns.heatmap(confusion_matrix(y_test, pred10), annot=True, fmt='d', cmap='Spectral')
print(classification_report(y_test, pred10))
print('\n')
            При K=10
[[65  3]
 [ 3 29]]
              precision    recall  f1-score   support
           0       0.96      0.96      0.96        68
           1       0.91      0.91      0.91        32
    accuracy                           0.94       100
   macro avg       0.93      0.93      0.93       100
weighted avg       0.94      0.94      0.94       100
          K = 5 и K = 10 имеют почти одинаковую точность, полноту и F1-меру.
knn35 = KNeighborsClassifier(n_neighbors = 35)
knn35.fit(X_train.values, y_train.values)
pred35 = knn35.predict(X_test.values)
print('При K=35')
print(confusion_matrix(y_test, pred35))
sns.heatmap(confusion_matrix(y_test, pred35), annot=True, fmt='d', cmap='Spectral')
print(classification_report(y_test, pred35))
print('\n')
            При K=35
[[65  3]
 [10 22]]
              precision    recall  f1-score   support
           0       0.87      0.96      0.91        68
           1       0.88      0.69      0.77        32
    accuracy                           0.87       100
   macro avg       0.87      0.82      0.84       100
weighted avg       0.87      0.87      0.87       100
          Метод опорных векторов (SVM, Support vector machines) использует гиперплоскость, чтобы классифицировать данные по 2 классам.
Метод опорных векторов - это метод "обучения с учителем", использующий классификацию, регрессию и определение выбросов (outlier). Главное преимущество SVM заключается в том, что он эффективен в многомерном пространстве, даже когда количество выборок меньше количества измерений. Но в случаях, когда измерения превышают количество образцов, есть вероятность переобучения.
Основная цель алгоритма SVM - создать оптимальную линию или границу решения, представляющую собой гиперплоскость, которая может разделить n-мерное пространство на классы, чтобы в будущем можно было поместить новую точку данных в правильную категорию.
В отличие от других классификаторов, которые обращают внимание на все точки, этот метод сосредотачиваются только на точках, которые труднее всего классифицировать.
Гиперплоскость - это подпространство, размерность которого на единицу меньше, чем размер его окружающего пространства или пространства, окружающего объект. Если пространство
- трехмерно, то его гиперплоскости являются двумерными,
 - двумерно, его гиперплоскости являются одномерными линиями,
 - одномерное, его гиперплоскость представляет собой единственную точку.
 
SVM использует набор математических функций, известных как ядро, для создания границы оптимального решения, принимая данные в качестве входных. Наиболее предпочтительный вид функции ядра - это RBF. Потому что он локализован и имеет конечный отклик по всей оси абсцисс.
Если данные слишком похожи или их сложно разделить по какой-либо причине, или из-за того, что они нелинейны, тогда SVM с ядром может добавить еще одно измерение с «гиперплоскостью», которая может разделить точки данных.
Значениями ядра могут быть:
- linear
 - poly
 - rbf (по умолчанию)
 - sigmoid
 - precomputed
 
SVM с линейным ядром
Это ядро лучше всего подходит для задач классификации, когда данные разделены линейно, как задача классификации текста.
# обучение модели
classifierLin = SVC(kernel = 'linear')
classifierLin.fit(X_train, y_train)
print(classifierLin.gamma)
print(classifierLin.C)
            scale 1.0
# проверка на тестовых данных
y_pred_svc = classifierLin.predict(X_test)
y_pred_svc
            array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
       0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1], dtype=int8)
          # анализ результатов
# матрица ошибок
cm2 = confusion_matrix(y_test, y_pred_svc)
print(cm2)
            [[66 2] [10 22]]
sns.heatmap(cm2, annot=True, fmt='d', cmap='Spectral')
plt.show()
            11 неверных прогнозов из 100.
print(classification_report(y_test, y_pred_svc))
                          precision    recall  f1-score   support
           0       0.87      0.97      0.92        68
           1       0.92      0.69      0.79        32
    accuracy                           0.88       100
   macro avg       0.89      0.83      0.85       100
weighted avg       0.88      0.88      0.87       100
          Точность 88%, но полнота для совершенных покупок всего 69%.
SVM с ядром RBF (Radial Basis Function)
# обучение модели
classifierrbf = SVC(kernel = 'rbf')
classifierrbf.fit(X_train, y_train)
print(classifierLin.gamma)
print(classifierLin.C)
            scale 1.0
# проверка на тестовых данных
y_pred_rbf = classifierrbf.predict(X_test)
y_pred_rbf
            array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
       0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1,
       0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1,
       1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1], dtype=int8)
          # анализ результатов
# матрица ошибок
cm3 = confusion_matrix(y_test, y_pred_rbf)
print(cm3)
            [[64 4] [ 3 29]]
7 неверных прогнозов из 100.
print(classification_report(y_test,y_pred_rbf))
                          precision    recall  f1-score   support
           0       0.96      0.94      0.95        68
           1       0.88      0.91      0.89        32
    accuracy                           0.93       100
   macro avg       0.92      0.92      0.92       100
weighted avg       0.93      0.93      0.93       100
          Общая точность (accuracy) составляет 93%, а точность (precision), полнота (recall) и F1-мера для предсказания "не покупок" выше 94%, а для проноза покупок близка к 90%.
Оптимизация гиперпараметров - это метод выбора набора оптимальных гиперпараметров для алгоритма обучения. Модель машинного обучения может иметь разные ограничения, веса или скорости обучения для обобщения различных шаблонов данных. Эти меры называются гиперпараметрами и должны быть настроены так, чтобы модель могла оптимально решить проблему машинного обучения. Основное различие между параметрами и гиперпараметрами заключается в том, что параметры изучаются автоматически, а значения гиперпараметров устанавливаются вручную.
Результатом оптимизации гиперпараметров является единый набор хорошо работающих гиперпараметров, которые можно настроить для модели для достижения наилучших результатов. Для получения оптимальных гиперпараметров существуют различные подходы к поиску, такие как: поиск по сетке (Grid Search), случайный поиск (Random Search), байесовская оптимизация (Bayesian optimization), оптимизация на основе градиента (Gradient-based optimization), оптимизация на основе эволюции (Evolutionary optimization), на основе популяции (Population-based). Рассмотрим поиск по сетке.
Поиск по сетке - это своего рода процесс настройки, который выбирает лучшие параметры для алгоритма для оптимизации его производительности, но его выполнения требует довольно много времени. Параметры оценивания, используемого для применения этих методов, оптимизируются с помощью поиска по сетке с перекрестной проверкой по сетке параметров. Функция GridSearchCV реализует методы «соответствия» и «оценки».
При обучении SVM необходимо учитывать два параметра:
- 
          
C
 - 
          
gamma
 
Используя поиск по сетке, можно найти наилучшее оптимальное значение для C и гаммы, а также лучшее ядро для SVM.
Параметр C
Реализация SVC основана на libsvm (библиотека для машин опорных векторов). C - параметр регуляризации в SVC и его значение с плавающей запятой по умолчанию 1. Сила регуляризации обратно пропорциональна C. Она должна быть строго положительной.
C определяет компромисс между увеличением размера поля и обеспечением того, чтобы точки обучения лежали на правильной стороне поля. Если значение C мало, это создаст разделяющую гиперплоскость с большим запасом, что может неправильно классифицировать больше точек и приведет к большему количеству ошибок обучения модели. Если же значение C очень велико, оптимизатор выберет разделяющую гиперплоскость с меньшим запасом, которая будет правильно классифицировать тренировочные точки, но может привести к переобучению.
Выбор значения C имеет решающее значение для SVC и может быть выполнен путем настройки гиперпараметров.
Параметр gamma
Параметры гаммы можно рассматривать как инверсию радиуса влияния выборок, выбранных моделью в качестве опорных векторов, и это коэффициент ядра для 'rbf', 'poly' и 'sigmoid'. Значение гаммы по умолчанию - 'scale'. и его значение равно 1 / (n_features * X.var()).
Когда гамма очень мала, модель слишком ограничена и не может уловить сложность или «форму» данных. Но более высокое значение гаммы точно соответствует точкам обучающих данных, но приведет к переобучению.
# поиск опимальных гиперпараметров
g = GridSearchCV(estimator=SVC(),
            param_grid={'C': [1, 10], 'gamma': [1,0.1,0.01,0.001,0.0001,1.1,1.2], 'kernel': ('linear', 'rbf')})
g.fit(X_train,y_train)
            GridSearchCV(estimator=SVC(),
             param_grid={'C': [1, 10],
                         'gamma': [1, 0.1, 0.01, 0.001, 0.0001, 1.1, 1.2],
                         'kernel': ('linear', 'rbf')})
          Поиск по сетке дает комбинацию значений, которая имеет наивысшую точность среди всех значений.
g.best_params_
            {'C': 1, 'gamma': 1, 'kernel': 'rbf'}
          Лучшие параметры для метода SVM с ядром rbf определились как gamma = 1 и C = 1.
g.best_estimator_
            SVC(C=1, gamma=1)
# анализ на тестовых данных по полученным параметрам.
grid_pred = g.predict(X_test)
            # оценка результатов
print(confusion_matrix(y_test, grid_pred))
            [[64 4] [ 2 30]]
sns.heatmap(confusion_matrix(y_test,grid_pred), annot=True, fmt='d', cmap='Spectral')
plt.show()
            6 неверных предсказаний из 100.
print(classification_report(y_test, grid_pred))
                          precision    recall  f1-score   support
           0       0.97      0.94      0.96        68
           1       0.88      0.94      0.91        32
    accuracy                           0.94       100
   macro avg       0.93      0.94      0.93       100
weighted avg       0.94      0.94      0.94       100
          Общая точность (accuracy) составляет 94%, а точность (precision), полнота (recall) и F1-мера для предсказания "не покупок" выше 94%, а для проноза покупок близка к 92%.
        
а можно ссылку на датасет?
ОтветитьУдалить