Предобработка данных
Импорт необходимых библиотек, которых пока будет достаточно для первичного анализа
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()

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