Полная записная книжка Colab с использованием Dfault набора данных клиентов кредитных карт из UCI — AISeries — Episode #05

В этом посте мы собираемся понять алгоритм машины опорных векторов, используя scikit-learn.

Вот колаб блокнот: ссылка.

Что такое метод опорных векторов?

Простой способ разделить наблюдения на два класса — провести между ними линейную границу:

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

Который лучший?

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

Однако это означает, что даже точки, находящиеся далеко от границы, влияют на ее расположение.

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

Это основная идея классификации машины опорных векторов.

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

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

Эти наблюдения называются опорными векторами.

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

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

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

Линейные границы между классами подходят не для всех задач.

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

Отлично!

Теперь давайте напишем код.

01#Шаг — Откройте Google Colab и введите следующее:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

02#step — Теперь давайте импортируем нашу базу данных кредитных карт.

Я буду использовать набор данных клиентов кредитных карт по умолчаниюизКалифорнийского университета, Ирвин (UCI), репозиторий машинного обучения.

Информация об атрибутах:

This research employed a binary variable, default payment (Yes = 1, No = 0), as the response variable. This study reviewed the literature and used the following 23 variables as explanatory variables:`
X1: Amount of the given credit (NT dollar): it includes both the individual consumer credit and his/her family (supplementary) credit.
X2: Gender (1 = male; 2 = female).
X3: Education (1 = graduate school; 2 = university; 3 = high school; 4 = others)
X4: Marital status (1 = married; 2 = single; 3 = others).
X5: Age (year).
X6 - X11: History of past payment. We tracked the past monthly payment records (from April to September, 2005) as follows: X6 = the repayment status in September, 2005; X7 = the repayment status in August, 2005; . . .;X11 = the repayment status in April, 2005. The measurement scale for the repayment status is: -1 = pay duly; 1 = payment delay for one month; 2 = payment delay for two months; . . .; 8 = payment delay for eight months; 9 = payment delay for nine months and above.
X12-X17: Amount of bill statement (NT dollar). X12 = amount of bill statement in September, 2005; X13 = amount of bill statement in August, 2005; . . .; X17 = amount of bill statement in April, 2005.
X18-X23: Amount of previous payment (NT dollar). X18 = amount paid in September, 2005; X19 = amount paid in August, 2005; . . .;X23 = amount paid in April, 2005.

Чтобы импортировать базу данных, введите:

df = pd.read_excel('https://archive.ics.uci.edu/ml/machine-learning-databases/00350/default%20of%20credit%20card%20clients.xls', header=1)

03#Шаг — Немного информации о данных:

df.info()

04#step — Знакомство с типом данных:

df.head(10)

05#step — Переименуем последний столбец в DEFAULT:

df.rename({'default payment next month': 'DEFAULT'}, axis='columns', inplace=True)
df.head()

Что означает значение по умолчанию? 1)Невыполнение того, что требуется по долгу или закону: пренебрежение. 2) архаичное: ошибка.3)экономика: неуплата финансовых долгов была неплатежом по ее ипотечным кредитам.4) закон : неявка в требуемое время на судебное разбирательство. Ответчик находится в дефолте.

06#step — Удалить столбец ID, потому что он не информативен:

df.drop('ID', axis=1, inplace=True) 
df.head()

07#шаг — Работа с отсутствующими данными:

Во-первых, давайте посмотрим, какие данные находятся в каждом столбце:

df.dtypes

Мы видим, что каждый столбец имеет значение int64, что хорошо, поскольку говорит нам о том, что они не смешивают буквы и цифры :) Нет значений NA. Давайте удостоверимся, что каждый столбец содержит допустимые значения (см. описание выше).

Во-первых, колонка секса:

Пол (1 = мужской; 2 = женский):

print(df['SEX'].unique())
[2 1]

Образование (1 = аспирантура, 2 = университет, 3 = средняя школа, 4 = другое)

Значения 0,5 и 6 неизвестны. Возможно, что 0 — это отсутствующие данные, а 5 и 6 — не упомянутые категории. Это только предположение :)

print(df['EDUCATION'].unique())
[2 1 3 5 4 6 0]

Семейное положение (1 = женат, 2 = холост, 3 = другое)

print(df['MARRIAGE'].unique())
[1 2 3 0]

Как и ОБРАЗОВАНИЕ, БРАК содержит 0, который, как мы предполагаем, представляет недостающие данные.

len(df.loc[(df['EDUCATION'] == 0) | (df['MARRIAGE'] == 0)])
68
df_no_missing = df.loc[(df['EDUCATION'] != 0) & (df['MARRIAGE'] != 0)]
len(df_no_missing)
29932

То есть 30000–68 = 29932.

Просто занимаюсь математикой:

Отсутствующие данные представляют собой 0,0022 или не менее 0,23% базы данных :)

(1 - ((30000-68)/30000))*100
0.2266666666666639

08#step — теперь воспользуемся тепловой картой от seaborn:

import seaborn as sns
plt.figure(figsize=(8,6))
sns.heatmap(df_no_missing, yticklabels=False, cbar=False, robust=True,cmap='viridis')

ПЕРВАЯ ПОЛОВИНА БАЗЫ ДАННЫХ ГОТОВА К РАБОТЕ! (столбцы с 1 по 10;) Подтверждение того, что в двух приведенных выше столбцах ничего не пропущено:

print(df_no_missing['EDUCATION'].unique())
print(df_no_missing['MARRIAGE'].unique())
[2 1 3 5 4 6] 
[1 2 3]

09#step — Даунсэмплинг базы данных:

Давайте напомним себе, сколько клиентов в наборе данных:

len(df_no_missing)
29932

Почему даунсэмплинг? SVM лучше работает в разумной базе данных. Возьмем по 1000 в каждой категории.

Мы начнем с разделения базы данных на две части: одну для людей, которые регулярно платят (no_default) задолженность по кредитной карте, а другую — для людей, у которых долг не выплачивается (по умолчанию).

платеж по умолчанию (Да = 1, Нет = 0)

Первый для не-дефолта :)

from sklearn.utils import resample
df_no_default = df_no_missing[df_no_missing['DEFAULT']==0]
df_no_default_downsampled = resample(df_no_default, replace=False, n_samples=1000, random_state=42 )
len(df_no_default_downsampled)
1000

Теперь по умолчанию:/

from sklearn.utils import resample
df_default = df_no_missing[df_no_missing['DEFAULT']==1]
df_default_downsampled = resample(df_default, replace=False, n_samples=1000, random_state=42 )
len(df_default_downsampled)
1000

Теперь объединяем базы данных обратно:

df_downsample = pd.concat([df_no_default_downsampled, df_default_downsampled ])
len(df_downsample)
2000

10#шаг — Подготовка к обучению разделения данных:

X = df_downsample.drop('DEFAULT', axis=1).copy() 
# Alternatively:  X = df_dow.iloc[:, :-1].copy()
X.head()

y = df_downsample['DEFAULT'].copy()
y.head()

11#шаг — Процедуры горячего кодирования (категориальные данные):

X_encoded = pd.get_dummies(X, columns=['SEX', 'EDUCATION', 'MARRIAGE', 'PAY_0', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6'])
X_encoded.head()

12#шаг — Центрирование и масштабирование данных:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.3, random_state=42)
from sklearn.preprocessing import scale
X_train_scaled = scale(X_train)
X_test_scaled = scale(X_test)

13#шаг — Построение предварительной SVM (Подгонка модели к данным:):

from sklearn.svm import SVC
clf_svm = SVC(random_state = 42)
clf_svm.fit(X_train_scaled, y_train)
SVC(C=1.0, break_ties=False, cache_size=200, class_weight=None, coef0=0.0,     decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',     max_iter=-1, probability=False, random_state=42, shrinking=True, tol=0.001,     verbose=False)

14#шаг — Матрица путаницы:

from sklearn.metrics import confusion_matrix
from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(clf_svm, X_test_scaled, y_test, values_format='d', display_labels=['Did Not Default', 'Defaulted'])

Анализ матрицы путаницы:

Из 233 + 69 = 302 человек, не нарушивших обязательства, 69 человек не классифицировались (21%).

Из 125 + 173 = 298 человек, допустивших дефолт, 125 человек не классифицировались (41,610%).

Это неприемлемо!

Давайте исправим это! (по крайней мере, попробуйте :/)

15#шаг — Перекрестная проверка и GridSearch — Методы оптимизации:

from sklearn.model_selection import GridSearchCV
param_grid = {'C':[0.5,0.1,1,10,100,1000], 'gamma':['scale', 1,0.1, 0.01,0.001,0.0001], 'kernel':['rbf']}
# we including C=1 and gamma = 'scale' cause these are default
# values;
# rbf = radial basis function, cause typically it gives us the best
# performance
# visit: Radial basis function 
# https://en.wikipedia.org/wiki/Radial_basis_function
optimal_params = GridSearchCV(SVC(), param_grid, cv = 5, scoring='accuracy', verbose=3)

Теперь подгоняем масштабированные данные:

optimal_params.fit(X_train_scaled, y_train)
print(optimal_params.best_params_)

Идеальное значение для C = 0,5, что означает, что мы будем использовать регуляризацию, и идеальное значение для gamma = 0,01.

16#шаг — Делаем прогнозы:

Ideal value for C = .5, which mean we will use regularization, adn the ideal value for gamma = 0.01
clf_svm = SVC(random_state = 42, C=1, gamma=0.01)
clf_svm.fit(X_train_scaled, y_train)
SVC(C=1, break_ties=False, cache_size=200, class_weight=None, coef0=0.0,     decision_function_shape='ovr', degree=3, gamma=0.01, kernel='rbf',     max_iter=-1, probability=False, random_state=42, shrinking=True, tol=0.001,     verbose=False)

17#шаг — Снова матрица путаницы:

plot_confusion_matrix(clf_svm, X_test_scaled, y_test, values_format='d', display_labels=['Did Not Default', 'Defaulted'])

Анализ матрицы путаницы:

Из 236 + 66 = 302 человек, не нарушивших обязательства, 66 человек были классифицированы неправильно (21%).

Из 127 + 171 = 298 человек, допустивших дефолт, 127 человек были классифицированы неправильно (42,617%).

Чуть хуже :/

Почему?

Попробуем построить граф граничных областей решения.

Это очень сложный шаг. Каждый раз, когда вы запускаете его, он будет давать разные результаты:/

В любом случае, давайте начнем! Ключевым моментом здесь является уменьшение габаритов…

len(df_downsample.columns)
24

Для этого потребуется 24-мерный график. Это невозможно… как решить эту проблему?

Ответы:

PCA (анализ основных компонентов)

from sklearn.decomposition import PCA
pca = PCA()
X_train_pca = pca.fit_transform(X_train_scaled)
per_var = np.round(pca.explained_variance_ratio_*100, decimals=1)
labels = [str(x) for x in range(1, len(per_var)+1)]
plt.bar(x=range(1, len(per_var)+1), height=per_var)
plt.tick_params(axis='x', which = 'both', bottom=False, top=False, labelbottom=False)
plt.ylabel('Percentage of Explained Variance')
plt.xlabel('Principal Components')
plt.title('Scree Plot')
plt.show()

18#step — Переобучение данных:

Давайте переобучим данные с помощью PCA

pc1 Содержит координаты данных по оси X после PCA.

pc2 Содержит координаты данных по оси Y после PCA.

train_pc1_coords = X_train_pca[:, 0]
train_pc2_coords = X_train_pca[:, 1]
#Centering & Scaling
pca_train_scaled = scale(np.column_stack((train_pc1_coords, train_pc2_coords)))
param_grid = {'C':[0.5,0.1,1,10,100,1000], 'gamma':['scale', 1,0.1, 0.01,0.001,0.0001], 'kernel':['rbf']}
# we including C=1 and gamma = 'scale' cause these are default values;
# rbf = radial basis function, cause typically it gives us the best performance
# visit: Radial basis function https://en.wikipedia.org/wiki/Radial_basis_function
optimal_params = GridSearchCV(SVC(), param_grid, cv = 5, scoring='accuracy', verbose=3)
optimal_params.fit(pca_train_scaled, y_train)
print(optimal_params.best_params_)

19#шаг — Решение Баулдарского района:

import matplotlib.colors as colors
clf_svm = SVC(random_state=42, C=1000, gamma=0.001)
clf_svm.fit(pca_train_scaled, y_train)
X_test_pca = pca.transform(X_train_scaled)
test_pc1_coords = X_test_pca[:, 0]
test_pc2_coords = X_test_pca[:, 1]
x_min = test_pc1_coords.min()-1
x_max = test_pc1_coords.max()+1
y_min = test_pc2_coords.min()-1
y_max = test_pc2_coords.max()+1
xx, yy = np.meshgrid(np.arange(start=x_min, stop=x_max, step=0.1),np.arange(start=y_min, stop=y_max, step=0.1) )
Z = clf_svm.predict(np.column_stack((xx.ravel(), yy.ravel())))
Z = Z.reshape(xx.shape)
fig, ax = plt.subplots(figsize=(10,10))
ax.contourf(xx,yy, Z, alpha=0.1)
cmap = colors.ListedColormap(['#e41a1c', '#4daf4a'])
scatter = ax.scatter(test_pc1_coords, test_pc2_coords, c=y_train, cmap=cmap, s=100, edgecolors='k', alpha=0.7)
legend = ax.legend(scatter.legend_elements()[0], scatter.legend_elements()[1], loc='upper right')
legend.get_texts()[0].set_text('No Defaults')
legend.get_texts()[1].set_text('Yes Defaults')
ax.set_ylabel('PC2')
ax.set_xlabel('PC1')
ax.set_title('Decision Surface Using the PCA Transformed/Projected Features')
#plt.savefig('svm_defaults.png)
plt.show()

20#шаг — Вот и все:

print("We studied: 'default of credit card clients Data Set' from UCI.\nThat's it! I hope this helps!\nThank you!")
We studied: 'default of credit card clients Data Set' from UCI. That's it! I hope this helps! Thank you!

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

До скорого!

Желаю вам отличного дня!

Скачать файл для этого проекта

29_credit_card_svm.ipynb

Кредиты и ссылки

На основе: Машины опорных векторов в Python от начала до конца. https://youtu.be/8A7L0GsBiLQ от StatQuest с Джошем Стармером

Набор данных клиентов кредитных карт по умолчанию —Загрузить: Папка данных, Описание набора данных

ВОПРОСЫ-ОТВЕТЫ:

01# What is the decision boundary in a linear classification model?
A decision boundary is the region of a problem space in which the output label of a classifier is ambiguous. If the decision surface is a hyperplane, then the classification problem is linear, and the classes are linearly separable. 
02# What does it mean for a classification model to be is linear?
In the field of machine learning, the goal of statistical classification is to use an object’s characteristics to identify which class (or group) it belongs to. A linear classifier achieves this by making a classification decision based on the value of a linear combination of the characteristics.
03# Categorical data. What is it?
In statistics, a categorical variable is a variable that can take on one of a limited, and usually fixed, number of possible values, assigning each individual or other unit of observation to a particular group or nominal category on the basis of some qualitative property.(wikipedia)
04# Decision boundaries. What is it?
Decision boundaries are not always clear cut. That is, the transition from one class in the feature space to another is not discontinuous, but gradual. This effect is common in fuzzy logic based classification algorithms, where membership in one class or another is ambiguous.

Похожие сообщения

00#Эпизод — AISeries — ML — Введение в машинное обучение — что это такое и как оно развивается со временем?

01#Эпизод — AISeries — Huawei ML FAQ — Как получить сертификат HCIA?

02#Эпизод — AISeries — Снова FAQ по Huawei ML — Еще аннотации с пробного экзамена Huawei

03#Эпизод — AISeries — Искусственный интеллект в графике — Получение интуиции о сложной математике и многом другом

04#Эпизод — AISeries — Huawei ML FAQ — Advanced— Еще больше аннотаций с пробного экзамена Huawei

05#Эпизод — AISeries — SVM — Кредитная карта — От начала до конца — Полный блокнот Colab с использованием набора данных клиентов кредитных карт по умолчанию из UCI (этот)

06#Эпизод — AISeries — SVM — Рак молочной железы — От начала до конца — Полная записная книжка Colab с использованием набора данных клиентов кредитных карт по умолчанию из UCI

07#Эпизод — AISeries — SVM — Кексы или кексы? — От начала до конца — на основе поста Алисы Чжао