1. Постановка проблемы.

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

  1. Соберите данные.
  2. Предварительная обработка данных.
  3. Разработка функций
  4. Обучите модель.
  5. Оценка модели.
  6. Входные переменные:
    # данные клиента банка:
    1 - возраст (числовой)
    2 - должность: тип работы (категориальный: 'admin.', 'blue -сотрудник, предприниматель, домработница, менеджмент, пенсионер, самозанятый, услуги, студент, техник, безработный, неизвестный)
    3 - семейное положение: семейное положение (категориальное: «разведен», «женат», «холост», «неизвестно»; примечание: «разведен» означает разведенный или вдовец)
    4 - образование (категориальное: «базовый. 4 года») , 'basic.6y', 'basic.9y', 'high.school', 'безграмотный', 'professional.course', 'University.degree', 'unknown')
    5 - по умолчанию: имеет кредит в дефолт? (категорично: «нет», «да», «неизвестно»)
    6 - жилье: есть ли жилищная ссуда? (категорично: «нет», «да», «неизвестно»)
    7 - заем: есть ли личный заем? (категоричный: 'нет', 'да', 'неизвестно')
    # связанный с последним контактом текущей кампании:
    8 - контакт: тип связи контакта (категориальный: 'сотовый', 'телефон ')
    9 - month: месяц последнего контакта в году (категориальные:' jan ',' feb ',' mar ',…,' nov ',' dec ')
    10 - day_of_week: последний контакт день недели (категориальный: «пн», «вт», «ср», «чт», «пт»)
    11 - duration: длительность последнего контакта в секундах (числовое значение). Важное примечание: этот атрибут сильно влияет на цель вывода (например, если длительность = 0, то y = ’no’). Тем не менее, продолжительность вызова до выполнения вызова неизвестна. Кроме того, после окончания звонка, очевидно, известно y. Таким образом, эти входные данные должны быть включены только для целей сравнения и должны быть отброшены, если намерение состоит в том, чтобы иметь реалистичную модель прогнозирования.
    # другие атрибуты:
    12 - кампания: количество контактов, выполненных во время этой кампании и для этого клиента (числовой, включая последний контакт)
    13 - дней: количество дней, прошедших после того, как с клиентом последний раз связались из предыдущей кампании (числовое значение; 999 означает, что с клиентом ранее не связались)
    14 - предыдущий: количество контактов, выполненных до этой кампании и для этого клиента (числовое значение)
    15 - poutcome: результат предыдущей маркетинговой кампании (категориальные: «неудача», «несуществующий», «успех»)
    # атрибуты социально-экономического контекста
    16 - emp.var.rate: уровень изменения занятости - квартальный показатель (числовой)
    17 - cons.price.idx: индекс потребительских цен - месячный показатель (числовой)
    18 - cons.conf.idx: индекс потребительского доверия - месячный индикатор (числовой)
    19 - euribor3m: eu Ribor 3-месячная ставка - дневной показатель (числовой)
    20 - количество занятых: количество сотрудников - квартальный показатель (числовой)

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

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

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

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

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

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

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

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

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

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

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

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

3.1 Обработка пропущенных значений

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

В наборе данных 41188 строк. Из них: 'работа', 'семейная жизнь', 'образование', 'по умолчанию', 'жилье', 'ссуда', 'контакт', 'месяц', 'день_недели', 'poutcome' категоричны. Остальные продолжаются. здесь ‘y’ - целевая переменная.

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

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

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

duration: продолжительность последнего контакта в секундах (числовое значение). Важное примечание: этот атрибут сильно влияет на цель вывода (например, если длительность = 0, то y = ’no’). Тем не менее, продолжительность вызова до выполнения вызова неизвестна. Кроме того, после окончания звонка, очевидно, известно 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 значения должны быть представлены числовыми значениями.

Затем f eatures job, marital, education, default, жильё, ссуда, month, day_of_week и poutcome используют горячую кодировку, поскольку они имеют более двух уникальных значений.

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, pdays, previous не зависят.

Давайте сравним характеристики с целевой переменной (рис. 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 обычно используется как метод извлечения признаков для уменьшения размеров набора данных. Это неконтролируемый статический метод, который используется для определения взаимосвязи между элементами.

При использовании атрибута объясненная_вариация_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 с двумя классами (синий, красный) лежат в 2-мерном векторном пространстве следующим образом. Здесь мы можем идентифицировать множество гиперплоскостей для разделения точек данных. Следовательно, мы должны выбрать оптимальную гиперплоскость. Оптимальная гиперплоскость дается, когда мы выбираем гиперплоскость с максимальным запасом расстояния до противоположных точек данных. Здесь точки данных, которые помогают найти оптимальную гиперплоскость, известны как опорные векторы (рис. 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).

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

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

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-классификация-модель-банк-маркетинг
Содействуйте развитию KuWathsala / ml-классификации-модели-банка-маркетинга, создав учетную запись на GitHub. github.com



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







Больше контента на plainenglish.io



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