Работы по машинному обучению 3ИСиП-19-1

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Предобработка данных

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

import pandas as pd
import numpy as np

Импортируем данные из файла в переменную и просматриваем содержимое

data_frame = pd.read_csv('bank.csv')
data_frame
data_frame.info()

Начинаю с самого простого - бинарные признаки default, housing, loan.

data_frame['default'] = np.where(data_frame['default'] == 'yes', 1, 0)
data_frame['housing'] = np.where(data_frame['housing'] == 'yes', 1, 0)
data_frame['loan'] = np.where(data_frame['loan'] == 'yes', 1, 0)

Надобность столбцов Day, Mounth и Contact под сомнением, так как по логике я считаю, что они не влияют на конечный результат.

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

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

data_frame.drop(['day', 'month', 'contact'], axis = 1, inplace = True)

Для удобства в дальнейшей работе разделю исходный набор данных - на числовой и объектовый

object_df = data_frame.select_dtypes(include=['object']).copy()
value_df = data_frame.select_dtypes(include=[int]).copy()
value_df
object_df

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

object_df['job'].value_counts()

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

target = value_df['y']
value_df.drop('y', axis = 1, inplace = True)

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

object_df_encoded = pd.get_dummies(object_df)
object_df_encoded

Выделить наиболее влияющие признаки на 'подпишется ли клиент на срочный депозит' и в дальнейшем использовать только их.

from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel
randomforest = RandomForestClassifier(random_state = 0, n_jobs = -1)
selector = SelectFromModel(randomforest, threshold = 0.1)
val_important = selector.fit_transform(value_df, target)
val_important

Так, уже какие-то зависимости найдены, а что если попробовать обработать числовые данные? Например прошкалировать или нормализовать?

from sklearn.preprocessing import StandardScaler, Normalizer

scaler = StandardScaler()
value_df_scaled = scaler.fit_transform(value_df) 

normalizer = Normalizer()
value_df_normalized = normalizer.fit_transform(value_df)

val_important_sc = selector.fit_transform(value_df_scaled, target)
val_important_sc

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

val_important_nr = selector.fit_transform(value_df_normalized, target)
val_important_nr

Признаков стало больше. Но хорошо ли это? Проверю в конечном анализе.
С помощью модели случайного леса можно так же посмотреть на коэффициенты важности признаков и на их основе построить диаграмму.

import matplotlib.pyplot as plt
rf_model = randomforest.fit(value_df, target)
names = value_df.columns.values
ticks = [i for i in range(len(rf_model.feature_importances_))]

plt.figure()
plt.title('Важность признаков')
plt.bar(names, rf_model.feature_importances_)
plt.xticks(ticks, names, rotation = 90)
plt.show()

Ну вот, и на диаграмме сразу стало видно, какие столбцы выводит SelectFromModel с порогом 0.1. А что покажет нормализация?

rf_model = randomforest.fit(value_df_normalized, target)
names = value_df.columns.values
ticks = [i for i in range(len(rf_model.feature_importances_))]

plt.figure()
plt.title('Важность признаков')
plt.bar(names, rf_model.feature_importances_)
plt.xticks(ticks, names, rotation = 90)
plt.show()

Как-то не однозначно, не стоит сразу этому доверять, проверим это на обучении.

Так же не забываем найти и значимые признаки среди закодированных категорий.

obj_important = selector.fit_transform(object_df_encoded, target)
obj_important

Не густо, надо вывести диаграмму.

rf_model = randomforest.fit(object_df_encoded, target)
names = object_df_encoded.columns.values
ticks = [i for i in range(len(rf_model.feature_importances_))]

plt.figure()
plt.title('Важность признаков')
plt.bar(names, rf_model.feature_importances_)
plt.xticks(ticks, names, rotation = 90)
plt.show()
Важность признаков
Важность признаков

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

Необходимо разделить данные на обучающую и тестовую выборки в соотношении 80%, 20%.

from sklearn.model_selection import train_test_split

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

features = np.array(pd.DataFrame(val_important).join(pd.DataFrame(obj_important), rsuffix='_obj'))
features_train, features_test, target_train, target_test = train_test_split(features, target, test_size = 0.20, random_state = 0)

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

# импортируем модели, с помощью которых будеи проводить анализ
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
from sklearn.naive_bayes import GaussianNB 
# этот медот понадобится для оценки точности обченной модели
from sklearn.metrics import accuracy_score 

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

kn_model = KNeighborsClassifier(n_neighbors = 20)
rfc_model = RandomForestClassifier(random_state = 0)
ada_model = AdaBoostClassifier(random_state = 0)
gnb_model = GaussianNB()

Обучаем все выбранные модельки на тренировочных выборках.

kn_model.fit(features_train, target_train)
rfc_model.fit(features_train, target_train)
ada_model.fit(features_train, target_train)
gnb_model.fit(features_train, target_train)

Теперь необходимо выполнить предсказания на каждой из моделей на тестовой выборке.

kn_predict = kn_model.predict(features_test)
rfc_predict = rfc_model.predict(features_test)
ada_predict = ada_model.predict(features_test)
gnb_predict = gnb_model.predict(features_test)

И на основе этих предсказаний проверяем точность моделей по ответам из тестовой выборки.

print('KNeighbors', accuracy_score(kn_predict, target_test))
print('RandomForest', accuracy_score(rfc_predict, target_test))
print('AdaBoost', accuracy_score(ada_predict, target_test))
print('GaussianNB', accuracy_score(gnb_predict, target_test))

Теперь для наглядности построим диаграмму точности каждой из моделей(хоть и значения отличаются на сотые).

names = ['KNeighbors', 'RandomForest', 'AdaBoost', 'GaussianNB']
ticks = [i for i in range(len(names))]
values = [accuracy_score(kn_predict, target_test), accuracy_score(rfc_predict, target_test),
         accuracy_score(ada_predict, target_test), accuracy_score(gnb_predict, target_test)]

plt.figure()
plt.title('Важность признаков')
plt.barh(names, values)
plt.yticks(ticks, names, rotation = 0)
plt.show()

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

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

Источник: https://habr.com/ru/post/595429/


Интересные статьи

Интересные статьи

На митапе 28 апреля С++ программисты из Luxoft расскажут о своих разработках в Automotive и банкинге.Под катом вся информация о докладах и регистрации. Чи...
Мне встречалось множество рекомендаций о повышении безопасности использования shell-скриптов в Bash путём включения опции pipefail (например — это рекомендуется в данном материале 2015 го...
Привет, Хабр! Сегодня делимся гайдом по началу работы с Windows Terminal. Да, поскольку он о начале работы с инструментом, в основном в материале описываются какие-то базовые моменты. Но ...
Меня зовут Александр, я аналитик отдела ИБ-аутсорсинга «СёрчИнформ». Настраиваю DLP, выявляю и анализирую инциденты, формирую отчеты для заказчика, предотвращаю сливы инф...
Инженер Рафаел Саргсян в советские годы работал в Ереванском НИИ математических машин и занимался созданием автоматизированных систем управления для военных объектов. В интервью м...