Постановка задачи:

В этом проекте мы собираемся классифицировать класс клиента, будь то 0 или 1.

Это проблема бинарной классификации (обучение с учителем).

Ссылка на набор данных: https://raw.githubusercontent.com/subashgandyer/datasets/main/great_customers.csv

Давайте прыгать прямо в!

Импорт необходимых библиотек

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import rcParams
from matplotlib.cm import rainbow
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')

Чтение данных

data=pd.read_csv("https://raw.githubusercontent.com/subashgandyer/datasets/main/great_customers.csv")
data

13599 строк × 15 столбцов

Проверка дисбаланса данных

data.great_customer_class.value_counts().plot.pie(autopct='%.2f')

Данные сильно несбалансированы

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

Метрика производительности

Precision/Specificity: сколько выбранных экземпляров релевантно.

Отзыв/Чувствительность: сколько релевантных экземпляров выбрано.

Оценка F1: среднее гармоническое точности и полноты.

AUC: соотношение между истинно положительными показателями и ложноположительными показателями

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

data.head(5)

Форма

data.shape
(13599, 15)

Функции

data.columns
Index(['user_id', 'age', 'workclass', 'salary', 'education_rank',
       'marital-status', 'occupation', 'race', 'sex', 'mins_beerdrinking_year',
       'mins_exercising_year', 'works_hours', 'tea_per_year',
       'coffee_per_year', 'great_customer_class'],
      dtype='object')

проверить недостающие значения

data.isna().sum()
user_id                      0
age                        421
workclass                  543
salary                     422
education_rank               0
marital-status               0
occupation                 543
race                         0
sex                          0
mins_beerdrinking_year     424
mins_exercising_year       421
works_hours                  0
tea_per_year              2429
coffee_per_year           2411
great_customer_class         0
dtype: int64
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13599 entries, 0 to 13598
Data columns (total 15 columns):
 #   Column                  Non-Null Count  Dtype  
---  ------                  --------------  -----  
 0   user_id                 13599 non-null  int64  
 1   age                     13178 non-null  float64
 2   workclass               13056 non-null  object 
 3   salary                  13177 non-null  float64
 4   education_rank          13599 non-null  int64  
 5   marital-status          13599 non-null  object 
 6   occupation              13056 non-null  object 
 7   race                    13599 non-null  object 
 8   sex                     13599 non-null  object 
 9   mins_beerdrinking_year  13175 non-null  float64
 10  mins_exercising_year    13178 non-null  float64
 11  works_hours             13599 non-null  int64  
 12  tea_per_year            11170 non-null  float64
 13  coffee_per_year         11188 non-null  float64
 14  great_customer_class    13599 non-null  int64  
dtypes: float64(6), int64(4), object(5)
memory usage: 1.6+ MB

Проверка процента отсутствующего значения

for i in range(len(data.columns)):
missing_data = data[data.columns[i]].isna().sum()
perc = missing_data / len(data) * 100
print(f'Feature {i+1} >> Missing entries: {missing_data}  |  Percentage: {round(perc, 2)}')
Feature 1 >> Missing entries: 0  |  Percentage: 0.0
Feature 2 >> Missing entries: 421  |  Percentage: 3.1
Feature 3 >> Missing entries: 543  |  Percentage: 3.99
Feature 4 >> Missing entries: 422  |  Percentage: 3.1
Feature 5 >> Missing entries: 0  |  Percentage: 0.0
Feature 6 >> Missing entries: 0  |  Percentage: 0.0
Feature 7 >> Missing entries: 543  |  Percentage: 3.99
Feature 8 >> Missing entries: 0  |  Percentage: 0.0
Feature 9 >> Missing entries: 0  |  Percentage: 0.0
Feature 10 >> Missing entries: 424  |  Percentage: 3.12
Feature 11 >> Missing entries: 421  |  Percentage: 3.1
Feature 12 >> Missing entries: 0  |  Percentage: 0.0
Feature 13 >> Missing entries: 2429  |  Percentage: 17.86
Feature 14 >> Missing entries: 2411  |  Percentage: 17.73
Feature 15 >> Missing entries: 0  |  Percentage: 0.0

Визуализация пропущенных значений

plt.figure(figsize=(10,6))
sns.heatmap(data.isna(), cbar=False, cmap='viridis', yticklabels=False)
<AxesSubplot:>

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

data['workclass']= data['workclass'].fillna('U')
data['occupation']= data['occupation'].fillna('U')
data.isnull().sum()
user_id                      0
age                        421
workclass                    0
salary                     422
education_rank               0
marital-status               0
occupation                   0
race                         0
sex                          0
mins_beerdrinking_year     424
mins_exercising_year       421
works_hours                  0
tea_per_year              2429
coffee_per_year           2411
great_customer_class         0
dtype: int64

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

from numpy import NaN
data[['age','salary','mins_beerdrinking_year','mins_exercising_year','tea_per_year','coffee_per_year']] = data[['age','salary','mins_beerdrinking_year','mins_exercising_year','tea_per_year','coffee_per_year']].replace(0, NaN)
data.fillna(data.mean(), inplace=True)
data

Выходные характеристики:

data_output_features=data.great_customer_class.drop_duplicates()
data_output_features
0        0
12431    1
Name: great_customer_class, dtype: int64

Нулевые пропущенные значения

data.isnull().sum()
user_id                   0
age                       0
workclass                 0
salary                    0
education_rank            0
marital-status            0
occupation                0
race                      0
sex                       0
mins_beerdrinking_year    0
mins_exercising_year      0
works_hours               0
tea_per_year              0
coffee_per_year           0
great_customer_class      0
dtype: int64

Обработка категориальных данных

from sklearn.preprocessing import LabelEncoder
labelencoder_X=LabelEncoder()
xm=data.apply(LabelEncoder().fit_transform)
xm

Входные функции

X=xm.iloc[:,:-1]
X

Выходные характеристики

y=xm.iloc[:,7]
y
0        1
1        0
2        0
3        0
4        1
        ..
13594    0
13595    0
13596    0
13597    0
13598    0
Name: race, Length: 13599, dtype: int32

Важность функции

#importing the ExtraTreesRegressor
from sklearn.ensemble import ExtraTreesClassifier
import matplotlib.pyplot as plt
model = ExtraTreesClassifier()
model.fit(X,y)
print(model.feature_importances_)
[5.15922695e-03 6.52201813e-03 9.97480198e-03 6.75190966e-03
 5.17079298e-03 4.79258824e-03 5.13421973e-03 9.32278250e-01
 9.24679975e-03 8.57937431e-04 6.37238179e-04 3.12327395e-03
 3.37443667e-03 6.97650620e-03]
#Top 5 important features
feat_importances = pd.Series(model.feature_importances_, index=X.columns)
feat_importances.nlargest(5).plot(kind='barh')
plt.show()
#X.columns
X_new = X[['occupation','user_id','salary','workclass','race']]
X_new

Разделить данные

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_new, y, test_size = 0.30, random_state=5)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
(9519, 5)
(4080, 5)
(9519,)
(4080,)

Построение модели

КНН

from sklearn.neighbors import KNeighborsClassifier
knn_classifier = KNeighborsClassifier()
knn_classifier.fit(X_train, y_train)
knn_predictions = knn_classifier.predict(X_test)
print(knn_classifier.score(X_test, y_test))
print(knn_classifier.score(X_train, y_train))
0.8960784313725491
0.9083937388381133
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,knn_predictions)
array([[3643,   49],
       [ 375,   13]], dtype=int64)

Случайный лес

from sklearn.ensemble import RandomForestClassifier
rf_classifier = RandomForestClassifier()
rf_classifier.fit(X_train, y_train)
rf_predictions = rf_classifier.predict(X_test)
print(rf_classifier.score(X_test, y_test))
print(rf_classifier.score(X_train, y_train))
1.0
1.0
#overfitting
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,rf_predictions)
array([[3692,    0],
       [   0,  388]], dtype=int64)

Логистическая регрессия

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
print(model.score(X_test, y_test))
print(model.score(X_train, y_train))
lr_predictions=model.predict(X_test)
0.903921568627451
0.9038764576110936

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

from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,lr_predictions)
array([[3685,    7],
       [ 385,    3]], dtype=int64)

SVM

from sklearn import svm
Sv_Classifier= svm.SVC()
Sv_Classifier.fit(X_train, y_train)
SVC()
Sv_predictions = Sv_Classifier.predict(X_test)
print(Sv_Classifier.score(X_test, y_test))
print(Sv_Classifier.score(X_train, y_train))
0.9049019607843137
0.9056623594915433
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,Sv_predictions)
array([[3692,    0],
       [ 388,    0]], dtype=int64)

Наивный Байес

from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
nb=gnb.fit(X_train, y_train)
nb
GaussianNB()
y_pred = gnb.predict(X_test)
y_pred
array([0, 0, 0, ..., 0, 0, 0])
print(gnb.score(X_test, y_test))
print(gnb.score(X_train, y_train))
1.0
1.0
#overfitting
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,y_pred)
array([[3692,    0],
       [   0,  388]], dtype=int64)

Заключение

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

from sklearn.ensemble import VotingClassifier
model_ensemble = VotingClassifier(estimators=[('lr', model), ('RF', rf_classifier), ('knn', knn_classifier ),("nb",gnb),("svc",Sv_Classifier)], voting='hard')
model_ensemble.fit(X_train, y_train)
VotingClassifier(estimators=[('lr',
                              VotingClassifier(estimators=[('lr',                                                         LogisticRegression()),
                                                           ('RF',
                                                            RandomForestClassifier()),
                                                           ('knn',
                                                            KNeighborsClassifier()),
                                                           ('nb', GaussianNB()),
                                                           ('svc', SVC())])),
                             ('RF', RandomForestClassifier()),
                             ('knn', KNeighborsClassifier()),
                             ('nb', GaussianNB()), ('svc', SVC())])
print(model_ensemble.score(X_test, y_test))
print(model_ensemble.score(X_train, y_train))
0.9088235294117647
0.9171131421367791
y_pred_en = model_ensemble.predict(X_test)
y_pred_en
array([0, 0, 0, ..., 0, 0, 0])
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,y_pred_en)
array([[3692,    0],
       [ 372,   16]], dtype=int64)

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

print('\n                     Accuracy     Error')
print('                     ----------   --------')
print('Logistic Regression    : {:.04}%       {:.04}%'.format(model.score(X_test, y_test)* 100,\
100-(model.score(X_test, y_test) * 100)))
print('KNN                    : {:.04}%       {:.04}% '.format(knn_classifier.score(X_test, y_test) * 100,\
100-(knn_classifier.score(X_test, y_test) * 100)))
print('Random Forest          : {:.04}%       {:.04}% '.format(rf_classifier.score(X_test, y_test)* 100,\
100-(rf_classifier.score(X_test, y_test)* 100)))
print('Naivebayes             : {:.04}%       {:.04}% '.format(gnb.score(X_test, y_test)* 100,\
100-(gnb.score(X_test, y_test)* 100)))
print('Support Vector Machine : {:.04}%       {:.04}% '.format(Sv_Classifier.score(X_test, y_test)* 100,\
100-(Sv_Classifier.score(X_test, y_test)* 100)))
print('                     ----------   --------')
print('Ensembling             : {:.04}%       {:.04}% '.format(model_ensemble.score(X_test, y_test)* 100,\
100-(model_ensemble.score(X_test, y_test)* 100)))
Accuracy     Error
                     ----------   --------
Logistic Regression    : 90.88%       9.118%
KNN                    : 89.61%       10.39% 
Random Forest          : 100.0%       0.0% 
Naivebayes             : 100.0%       0.0% 
Support Vector Machine : 90.49%       9.51% 
                     ----------   --------
Ensembling             : 90.88%       9.118%