Предобработка данных
Импорт необходимых библиотек, которых пока будет достаточно для первичного анализа
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()
Можно сделать вывод, что для дальнейшего анализа стоит использовать гауссов наивный классификатор, так как из одинаковых для всех моделей обучающего и тестового наборов этот алгоритм показал наивысшую точность.
Но точность все равно не дотягивает до идеальной, что можно сделать? Неужели придется перебирать еще кучу моделей? Так же не стоит забывать и про сам набор данных. Стоит вернуться к предобработке исходного набора и поэкспериментировать с данными. Вероятно может быть даже так, что удаленный столбец улучшит результат, а тот, который остался ухудшает и его наоборот стоит удалить.
MockBeard
Когда-нибудь, из-за таких КПВД, как ваша, я перестану заходить на хабр. Помогите мне сэкономить время!!!