Реализуйте модель классификации с помощью машины опорных векторов (SVM).

Сегодня мы собираемся разработать модель классификации машинного обучения с помощью машины опорных векторов (SVM). Здесь мы не собираемся обсуждать теоретическую концепцию машинного обучения, а сосредоточимся на реализации модели машинного обучения. Итак, я думаю, у вас есть базовые знания о концепции машинного обучения и Python. Мы реализуем модель со следующими шагами.

  1. Соберите данные.
  2. Предварительная обработка данных.
  3. Разработка функций
  4. Обучите модель.
  5. Оценка модели.
  6. Входные переменные:
    данные # банка-клиента:
    1 — возраст (числовой)
    2 — должность: тип работы (категория: 'администратор', 'синий -воротник','предприниматель','домработница','руководство','пенсионерка','самозанятый','услуги','студент','техник','безработный','неизвестно')
    3 — семейный: семейное положение (категория: «разведен», «замужем», «холост», «неизвестно»; примечание: «разведен» означает разведенный или вдовец)
    4 — образование (категория: «базовое.4г» ,'базовый.6г','базовый.9л','высшая.школа','неграмотный','профессиональный.курс','университетская.степень','неизвестно')
    5 — по умолчанию: имеет кредит в по умолчанию? (категория: «нет», «да», «неизвестно»)
    6 — жилье: есть жилищный кредит? (категория: «нет», «да», «неизвестно»)
    7 — кредит: есть потребительский кредит? (категория: 'нет','да','неизвестно')
    # относится к последнему контакту текущей кампании:
    8 — контакт: тип связи контакта (категория: 'сотовый','телефон ')
    9 — месяц: месяц последнего контакта в году (категория: 'янв', 'февраль', 'март', …, 'ноябрь', 'декабрь')
    10 — день_недели: последний контакт день недели (категория: 'пн', 'вт', 'ср', 'чт', 'пт')
    11 — продолжительность: продолжительность последнего контакта в секундах (числовое). Важное примечание: этот атрибут сильно влияет на цель вывода (например, если продолжительность = 0, то y = «нет»). Тем не менее, продолжительность не известна до выполнения вызова. Кроме того, после окончания вызова y, очевидно, известен. Таким образом, эти входные данные следует включать только в целях сравнительного анализа и от них следует отказаться, если намерение состоит в том, чтобы иметь реалистичную прогностическую модель.
    # другие атрибуты:
    12 — кампания: количество контактов, выполненных во время этой кампании и для этого клиента (числовое, включая последний контакт)
    13 — pdays: количество дней, прошедших с момента последнего контакта с клиентом из предыдущей кампании (числовое; 999 означает, что с клиентом ранее не связывались)
    14 — предыдущая: количество контактов, выполненных до этой кампании и для этого клиента (числовое)
    15 — результат: результат предыдущей маркетинговой кампании (категория: «неудача», «несуществующий», «успех»)
    # атрибуты социального и экономического контекста
    16 — emp.var.rate: коэффициент изменения занятости — квартальный показатель (числовой)
    17 — cons.price.idx: индекс потребительских цен — месячный показатель (числовой)
    18 — cons.conf.idx: индекс доверия потребителей — месячный показатель (числовой)
    19 — euribor3m: трехмесячный курс euribor — дневной показатель (числовой)
    20 — nr.employed: количество сотрудников — квартальный показатель (числовой)

    Выходная переменная (желаемая цель):
    21 — y — оформил ли клиент срочный депозит? (бинарный: «да», «нет»)

Прежде всего, давайте определим нашу проблемную область.

2. Соберите данные

Задача, которую мы собираемся реализовать, заключается в том,

Пример использования: набор банковских маркетинговых данных.

Набор данных связан с кампаниями прямого маркетинга (телефонными звонками) португальского банковского учреждения. Цель состоит в том, чтобы предсказать, подпишется ли клиент на срочный депозит?

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

3. Предварительная обработка данных

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

Набор данных для нашей задачи взят из Репозитория машинного обучения UCI: набор банковских маркетинговых данных.

Источник: «Репозиторий машинного обучения UCI: набор банковских маркетинговых данных»

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

3.1 Обработка отсутствующих значений

В качестве первого шага кодирования необходимо импортировать данные. Здесь файл CSV импортируется в Python с помощью Pandas (рис. 1).

В наборе данных 41188 строк. Из них"работа", "брак", "образование", "по умолчанию", "жилье", "кредит", "контакт", "месяц", "день_недели", "выход" являются категоричными. Другие непрерывны. здесь ‘y’ — целевая переменная.

banking_df = pd.read_csv(‘banking.csv’)

Когда мы рассматриваем набор данных, мы можем определить, что есть несколько нерелевантных функций в соответствии с проблемной областью.

«Продолжительность» упоминается, что,

продолжительность: продолжительность последнего контакта в секундах (числовое). Важное примечание: этот атрибут сильно влияет на цель вывода (например, если продолжительность = 0, то y = «нет»). Тем не менее, продолжительность не известна до выполнения вызова. Кроме того, после окончания вызова y, очевидно, известен. Таким образом, эти входные данные должны быть включены только для целей сравнительного анализа и должны быть отброшены, если намерение состоит в том, чтобы иметь реалистичную прогностическую модель.

Поэтому я удаляю столбец duration из набора данных.

В наборе данных нет нулевых значений (рис. 2).

df = banking_df.copy()
banking_df = banking_df.drop(['duration'], axis=1)

3.2 Удалить дубликаты

Когда мы работаем только с непрерывными функциями для обработки выбросов.

3.3 Обработка выбросов

# drop the duplicates
dups = df.duplicated()
print('before are there any duplicates : ', dups.any())
df.drop_duplicates(inplace=True)
# reset indices after dropping rows
df=df.reset_index(drop=True)
print('after are there any duplicates : ', df.duplicated().any())

3.4 Кодирование функций

Возраст находится между 17 и 98 годами. Однако мы можем видеть, что некоторые точки данных действуют как выбросы. Тем не менее, возраст контекстуально подходит для этого диапазона. Таким образом, нет необходимости удалять эти точки данных как выбросы в возрасте (рис. 4).

import scipy.stats as stats
import matplotlib.pyplot as plt
cols = ['age', 'campaign', 'emp_var_rate', 'cons_price_idx', 'cons_conf_idx', 'euribor3m','nr_employed']
for col in cols: 
    fig, axes = plt.subplots(nrows=1,ncols=3, figsize=(15, 4))
    fig.suptitle(col)
    axes[0].boxplot(df[col])
    axes[1].hist(df[col])
    stats.probplot(df[col], dist='norm', plot=axes[2])
    plt.show()

У emp_var_rate, cons_price_idx, euribor3m и nr_employed нет выбросов.

В кампании мы можем выявить выбросы и удалить их (рис. 6).

Кроме того, в cons_conf_idx мы можем определить выбросы и удалить их.

# remove outlier of campaign
fig, axes = plt.subplots(1,2)
df2 = df
col='campaign'
print("Before Shape:",df2.shape)
axes[0].title.set_text("Before")
sns.boxplot(df2[col],orient='v',ax=axes[0])
# Removing campaign above 50 
df2 = df2[ (df2[col]<50)]
print("After Shape:",df2.shape)
axes[1].title.set_text("After")
sns.boxplot(df2[col],orient='v',ax=axes[1])
df=df2;
plt.show()
# reset indices after dropping rows
df=df.reset_index(drop=True)

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

# remove outlier of cons_price_idx
fig, axes = plt.subplots(1,2)
plt.tight_layout(0.2)
df2 = df
col='cons_conf_idx'
print("Before Shape:",df2.shape)
axes[0].title.set_text("Before")
sns.boxplot(df2[col],orient='v',ax=axes[0])
# Removing cons_price_idx above -28 
df2 = df2[ (df2[col]<-28)]
print("After Shape:",df2.shape)
axes[1].title.set_text("After")
sns.boxplot(df2[col],orient='v',ax=axes[1])
df=df2;
plt.show()
# reset indices after dropping rows
df=df.reset_index(drop=True)

3.5 Преобразование данных

Проверим, сколько категориальных признаков (рис. 8),

Здесь мы видим контакт только двух уникальных значений (рис. 9). Таким образом, они могут быть просто закодированы метками, поскольку только 2 значения должны быть представлены числовыми значениями.

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

df['contact'] = df['contact'].astype('category').cat.codes

Здесь я делю первые девять столбцов на непрерывные признаки, а остальные — на категориальные признаки. Это помогает в будущем, когда вы работаете только с продолжающимися функциями.

from sklearn.preprocessing import OneHotEncoder
encoder=OneHotEncoder(sparse=False)
columns = ['job','marital','education','default','housing','loan','month','day_of_week','poutcome']
df_encoded = pd.DataFrame (encoder.fit_transform(df[columns]))
df_encoded.columns = encoder.get_feature_names(columns)
df.drop(columns ,axis=1, inplace=True)
df= pd.concat([df, df_encoded ], axis=1)

возраст, кампания и предыдущая перекошены вправо, а nr_employed перекошены влево (рис. 10).

3.6 Переменная дискретизация

Поэтому для уменьшения асимметрии и приведения к нормальному виду распределения применяется возраст, кампания и предыдущаятрансформация журнала.

nr_employedприменяется преобразование x².

#Do the logarithm trasnformations for required features
from sklearn.preprocessing import FunctionTransformer
logarithm_transformer = FunctionTransformer(np.log1p, validate=True)
# apply the transformation to your data
columns = ['age', 'campaign', 'previous']
to_right_skewed = logarithm_transformer.transform(df[columns])
df['age'] = to_right_skewed[:, 0]
df['campaign'] = to_right_skewed[:, 1]
df['previous'] = to_right_skewed[:, 2]

Дискретизация переменных преобразует непрерывные переменные в дискретные переменные. В основном существует 3 подхода к дискретизации: контролируемая, неконтролируемая и пользовательская дискретизация.

columns = ['nr_employed']
exp_transformer = FunctionTransformer(lambda x:x**2, validate=True) # FunctionTransformer(np.exp, validate=True) #
to_left_skewed = exp_transformer.transform(df[columns])
df['nr_employed'] = to_left_skewed[:, 0]

3.7 Масштабирование функций

Здесь мы используем неконтролируемый подход, называемый кластеризацией k-средних для непрерывных переменных, тогда каждый кластер рассматривается как бин. Здесь я использовал 10 бинов для функции age.

Масштабирование признаков Методы стандартизации позволяют нормализовать диапазон значений независимых переменных. Методы стандартной стандартизации и стандартизации s min max могут быть идентифицированы как методы стандартизации.

from sklearn.preprocessing import KBinsDiscretizer
data = pd.DataFrame(df, columns=['age'])
# fit the scaler to the  data
discretizer = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='kmeans') 
discretizer.fit(data)
_discretize = discretizer.transform(data)
x = pd.DataFrame(_discretize, columns=['age'])
df['age'] = x['age']

3.8 Разделение набора данных

Здесь я использовал стандартный метод стандартизации для масштабирования функций. стандартизация устанавливает 0 как среднее (μ) и стандартное отклонение (σ) как 1.

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

Здесь набор данных разделен на 2 части: набор данных для обучения и набор данных для тестирования. Здесь я использую 80 подарков для обучения и 20 подарков для тестирования.

from sklearn.preprocessing import StandardScaler
df2 = df
# Removing Categorical Features before the feature scaling
columns = df.columns
# Continous col
columns_cont = np.delete(columns,np.s_[9:])
# Categorical col
columns_categorical = np.delete(columns,np.s_[0:9])
# except age since it is discretized
except_age_cont = np.delete(columns_cont, [0])
# Applying Standardization 
# Init StandardScaler
scaler = StandardScaler()
#Transformation of training dataset features
Except = pd.DataFrame(df, columns = except_age_cont)
scaler.fit(Except)
df = pd.DataFrame(scaler.transform(Except), columns = except_age_cont).join(df[columns_categorical])
df = df.join(df2['age'])
# Get age in last column to first column
cols = list(df.columns)
cols = [cols[-1]] + cols[:-1]  #make last column first
df=df[cols]

4. Разработка функций

Кроме того, набор данных также разделен на независимые переменные и целевой набор данных, поскольку наша цель — предсказать кажущуюся температуру. Таким образом, «y» — это целевой набор данных, а остальные признаки взяты как независимые переменные (рис. 13).

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

from sklearn.model_selection import train_test_split
# set apparent temperature as target
columns_value = df.columns
index = np.argwhere(columns_value == 'y')
columns_value_new = np.delete(columns_value, index)
data = pd.DataFrame(df, columns=columns_value_new)
# target as Y
selected_columns = ['y']
y_true = df[selected_columns].copy()
# X as indipendent 
X = data
# create training and testing vars
X_train, X_test, y_train, y_test = train_test_split(X, y_true, test_size=0.2)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

4.1 Корреляционная матрица

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

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

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

r‹0,3 Нет или очень слабо

0,3 ≤r‹0,5 Слабый

0,5≤r‹0,7 Средняя

1≤r≤0,7 Сильный

Здесь мы рассматриваем только непрерывные признаки. По тепловой карте в наборе данных мы можем сделать вывод, что

nr_employed, euribor3m, emp_var_rate и emp_pricce_idx зависят друг от друга.

Возраст, кампания, cons_conf_idx, количество дней и предыдущее время не зависят друг от друга.

Давайте сравним признаки с целевой переменной (рис. 15).

#correlation matrix
df_for_feature_eng = df[columns_cont]
plt.figure(figsize=(16, 16))
# Set the range of values to be displayed on the colormap from -1 to 1, and set the annotation to True to display the correlation values on the heatmap.
plt.figure(figsize=(16, 6))
heatmap = sns.heatmap(df_for_feature_eng.corr(), vmin=-1, vmax=1, annot=True)
# Give a title to the heatmap. Pad defines the distance of the title from the top of the heatmap.

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

#correlation matrix
df_for_feature_eng = df[columns_cont]
df_for_feature_eng= df_for_feature_eng.join(df['y'])
plt.figure(figsize=(16, 16))
# Set the range of values to be displayed on the colormap from -1 to 1, and set the annotation to True to display the correlation values on the heatmap.
plt.figure(figsize=(16, 6))
heatmap = sns.heatmap(df_for_feature_eng.corr(), vmin=-1, vmax=1, annot=True)
# Give a title to the heatmap. Pad defines the distance of the title from the top of the heatmap.

Итак, я решил оставить nr_employedи отказаться от euribor3m, emp_var_rate и emp_pricce_idx, так как они зависят друг от друга. .

На следующем шаге мы пытаемся сократить количество признаков с помощью PCA.

# drop emp.var.rate, cons.price.idx ,euribor3m
X_train = X_train.drop('emp_var_rate', 1)
X_train = X_train.drop('cons_price_idx', 1)
X_train = X_train.drop('euribor3m', 1)
X_test = X_test.drop('emp_var_rate', 1)
X_test = X_test.drop('cons_price_idx', 1)
X_test = X_test.drop('euribor3m', 1)

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

5. Обучите модель

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

С помощью атрибута explained_variance_ratio_ первые основные компоненты дисперсии, содержащие до 95%, принимаются для обучения модели.

Обучающая модель состоит из 25 компонентов, содержащих 95% информации (рис. 16).

Следующим шагом является обучение реализованной модели. Здесь я использую машину опорных векторов (SVM) для реализации модели.

from sklearn.decomposition import PCA
# see explained variance ratios
pca = PCA()
pca.fit(X_train)
pca.explained_variance_ratio_

pca = PCA(n_components = 25)
pca.fit(X_train)
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

Метод опорных векторов (SVM)

SVM — это контролируемый (y — категориальный) алгоритм машинного обучения, который используется для моделей классификации. Модель работает лучше с ограниченным количеством данных и быстрее по сравнению с моделями нейронных сетей. SVM работает с бинарной классификацией, а также с многоклассовой классификацией. Здесь мы обсуждаем бинарную классификацию. Кроме того, он выполняет как линейные, так и нелинейные данные.

6. Оценка модели

В бинарной классификации, если можно провести линию (гиперплоскость), чтобы разделить точки данных на два класса, и точка данных принадлежит одному классу с каждой стороны, то она называется линейно разделимой. Например, функции X и Y с двумя классами (синий, красный) лежат в двумерном векторном пространстве следующим образом. Здесь мы можем определить множество гиперплоскостей для разделения точек данных. Следовательно, мы должны выбрать оптимальную гиперплоскость. Оптимальная гиперплоскость задается, когда мы выбираем гиперплоскость с максимальным запасом расстояния до противоположных точек данных. Здесь точки данных, которые поддерживают поиск оптимальной гиперплоскости, известны как опорные векторы (рис. 16).

Используется хитрость ядра, когда мы применяем линейный классификатор к нелинейным точкам данных. Здесь нелинейные точки данных сопоставляются с более высоким измерением, которое может быть линейно разделимым. Например, функции X и Y, которые нелинейно отделимы в двумерном векторном пространстве. Затем создается новое измерение (Z) и теперь можно использовать линейно разделяемое (рис. 18).

Модель дает на 89% более высокую точность (рис. 18), но мы не можем удовлетворить только значение точности, так как целевая переменная сильно несбалансирована (рис. 29).

#Import svm model
from sklearn import svm
#Create a svm Classifier
#gamma: Kernel coefficient for ‘rbf’, ‘poly’ and ‘sigmoid’. Higher the value of gamma, will try to exact fit the as per training data set i.e. generalization error and cause over-fitting problem.
clf = svm.SVC(kernel='rbf', gamma=1)
#Train the model using the training sets
clf.fit(X_train_pca, y_train)
#Predict the response for test dataset
y_pred = clf.predict(X_test_pca)

Матрица путаницы

Итак, давайте попробуем оценить производительность модели, используя матрицу путаницы.

#Import scikit-learn metrics module for accuracy calculation
from sklearn import metrics
# Model Accuracy: how often is the classifier correct?
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))

Матрица путаницы имеет 4 комбинации фактических и прогнозируемых значений (рис. 21). Давайте обсудим это на примере. Модель предсказывает появление цунами.

Заключение

1. TP: есть цунами, и модель также предсказала, что цунами будет.

2. TN: цунами нет, и модель также предсказала, что цунами не будет.

3. FP: цунами нет, но модель предсказала, что цунами будет.

4. FN: есть цунами, но модель предсказала, что цунами нет.

Отзыв: число правильно спрогнозированных как положительные (1) из класса фактически положительных (1).

Точность: число правильно спрогнозированных как положительные (1) из спрогнозированных как положительные (1) классы.

Точность: количество правильно предсказанных значений из всех классов.

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

cm = metrics.confusion_matrix(y_test, y_pred)
plt.figure(figsize = (8,8))
fig, ax = plt.subplots(1)
ax = sns.heatmap(cm, ax=ax, annot=True) #normalize='all'
plt.title('Confusion matrix')
plt.ylabel('True category')
plt.xlabel('Predicted category')
plt.show()

Из фактических точек данных, помеченных как 1 (TP + FN), модель определила больше точек данных как 0 (FN). Таким образом,можно сделать вывод, что модель работает плохо (рис. 22).

Рекомендуется

print("Precision : ", metrics.precision_score(y_test, y_pred))
print("Recall : ", metrics.recall_score(y_test, y_pred))
print("f1_score:", metrics.f1_score(y_test, y_pred, average="macro"))

В качестве решения мы можем порекомендовать сбалансировать целевой класс перед обучением модели. Если вы собираетесь балансировать классы имбаланса, вам рекомендуется «SMOTE». SMOTEиспользует методы передискретизации для балансировки классов дисбаланса.

Техника SMOTE используется только для обучающего набора данных.

После применения SMOTE в модель поезда берутся 23 признака (рис. 24).

from sklearn.model_selection import train_test_split
from imblearn.over_sampling import SMOTE
# create training and testing vars
X_train, X_test, y_train, y_test = train_test_split(X, y_true, test_size=0.3, random_state = 100)
smt = SMOTE(random_state = 101)
X_train, y_train = smt.fit_resample(X_train, y_train)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

Затем снова обучите модель.

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

#Import svm model
from sklearn import svm
#Create a svm Classifier
#gamma: Kernel coefficient for ‘rbf’, ‘poly’ and ‘sigmoid’.
clf = svm.SVC(kernel='rbf',  gamma=0.001, C=100)
#Train the model using the training sets
clf.fit(X_train_pca, y_train)
#Predict the response for test dataset
y_pred = clf.predict(X_test_pca)

Затем набор данных обучается усилению, и точность модели составляет 83%. Это показывает, что показатель точности модели снижается (рис. 25).

Однако матрица путаницы показывает некоторое улучшение модели (рис. 26). Однако запоминание улучшилось (62%). но точность становится низкой. Это означает, что

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

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

Ссылка

KuWathsala/ml-classification-model-bank-marketing
Внесите свой вклад в разработку KuWathsala/ml-classification-model-bank-marketing, создав учетную запись на GitHub.github.co



Определение проблемы.







Вариант использования машинного обучения: создание модели классификации для прогнозирования маркетинга банка.