https://app.powerbi.com/view?r=eyJrIjoiYjkzMjc0NDUtNzEwMi00NTgzLWE3MGItYzQ1OTg3NjEwNjcwIiwidCI6IjQ0ODdiNTJmLWYxMTgtNDgzMC1iNDlkLTNjMjk4Y2I3MTA3NSJ9

Введение

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

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

В этом проекте вы:

  1. Узнайте больше о моделях классификации и помогите клиенту, телекоммуникационной компании, понять свои данные.
  2. Найдите пожизненную ценность каждого клиента.
    узнайте, какие факторы влияют на скорость, с которой клиенты перестают пользоваться их сетью.
  3. спрогнозировать, уйдет клиент или нет

Наборы навыков, которые вы создадите:

1. Исследование данных
2. Вычисление пропущенных значений
3. Разработка признаков
4. Разработка модели с использованием алгоритмов машинного обучения, таких как логистическая регрессия, 5 5. Деревья решений, метод опорных векторов, случайный лес и т. д. .
6. Оценка и интерпретация модели с использованием методов LIME, SHAP
7 . Оптимизация модели и настройка гиперпараметров

Каталог:

*Установка и импорт важных функций

*Загрузка данных

* Оценка данных (Eda)

* Обработка данных и проектирование

*Проверка гипотез

* Ответы на вопросы с помощью визуализаций

*Развертывание Power Bi

* Балансировка набора данных

* Обучение и оценка четырех моделей

* Оценить выбранную модель

* Улучшение модели

* Прогнозы на будущее

*Ключевая информация и выводы

Установка и импорт полезных библиотек:

import sqlalchemy as sa
import pyodbc
from dotenv import dotenv_values
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import chi2_contingency
from scipy.stats import ttest_ind
from imblearn.over_sampling import SMOTE
from imblearn.combine import SMOTETomek
from imblearn.over_sampling import BorderlineSMOTE
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score
from sklearn.ensemble import StackingClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report

import os
import pickle
import shutil

import warnings
warnings.filterwarnings("ignore")

Загрузка данных:

Чтобы начать наше путешествие по анализу данных, нам нужно сначала загрузить данные из нескольких источников в среду нашего проекта. В этом разделе основное внимание уделяется процессу загрузки данных, где мы будем получать данные из трех разных источников: базы данных, GitHub и OneDrive.

Загрузка данных из базы данных. Первый источник наших данных находится в базе данных. У нас есть два варианта установления соединения и получения необходимых данных: с помощью импортированного ранее модуля pythonpyodbc или sqlalchemy. С помощью pyodbc мы можем подключиться к базе данных, используя соответствующие учетные данные, и установить соединение, которое сохраняется в файле .env в корне репозитория с помощью dotenv. Кроме того, sqlalchemyпредоставляет уровень абстракции для подключения к базе данных и упрощает процесс запроса данных.

# Load environment variables from .env file into a dictionary
environment_variables = dotenv_values('.env')


# Get the values for the credentials you set in the '.env' file
database = environment_variables.get("DATABASE")
server = environment_variables.get("SERVER")
username = environment_variables.get("USERNAME")
password = environment_variables.get("PASSWORD")
# Establishing the connection
connection_string = f"DRIVER={{SQL Server}};SERVER={server};DATABASE={database};UID={username};PWD={password}"

# Establish the connection using SQLAlchemy
engine = sa.create_engine(f"mssql+pyodbc:///?odbc_connect={connection_string}")
# Create a connection
connection = engine.connect()

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

# Execute the query
query = "SELECT * FROM dbo.LP2_Telco_churn_first_3000"
result = connection.execute(query)
# Fetch all the rows from the result set into a Pandas DataFrame
df = pd.DataFrame(result.fetchall(), columns=result.keys())

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

# reading csv data
df1 = pd.read_csv('C:\\Users\\X1 CARBON\\Downloads\\LP2_Telco-churn-last-2000.csv')

Загрузка данных из OneDrive. Третьим источником наших данных является OneDrive, облачное хранилище, предоставляемое Microsoft. OneDrive предлагает удобную платформу для хранения и обмена файлами, включая наборы данных. Подобно GitHub, OneDrive позволяет нам либо загружать набор данных напрямую, либо получать к нему доступ по общей ссылке.

#reading a xlsx file from the local storage
df_test = pd.read_excel('C:\\Users\\X1 CARBON\\Downloads\\Telco-churn-second-2000.xlsx')

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

Гипотеза и формулировка вопросов:

ГИПОТЕЗА!

НУЛЕВАЯ ГИПОТЕЗА: H0

АЛЬТЕРНАТИВНАЯ ГИПОТЕЗА: H1

H0 — существенной разницы в показателях оттока между клиентами-мужчинами и женщинами нет. H1 – Есть ли существенная разница в показателях оттока между клиентами-мужчинами и клиентами-женщинами?

H0 : Тип интернет-услуги не влияет на отток клиентов.

H1: Влияет ли тип интернет-услуг на отток клиентов?

H0 : Клиенты с более длительным сроком пребывания более склонны к оттоку.

H1: клиенты с более длительным сроком пребывания менее склонны к оттоку?

H0 — Способ оплаты не влияет на отток клиентов.

H1- Влияет ли способ оплаты на отток клиентов?

ВОПРОСЫ?

1. Есть ли существенная разница в показателях оттока между клиентами мужского и женского пола?

2. Влияет ли тип интернет-услуг на отток клиентов?

3. Вероятность оттока клиентов с более длительным стажем меньше?

4. Влияет ли способ оплаты на отток клиентов?

Оценка данных (EDA):

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

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

#show information about the dataset
df_train.info()

выход

<class 'pandas.core.frame.DataFrame'>
Int64Index: 5043 entries, 0 to 2042
Data columns (total 21 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   customerID        5043 non-null   object 
 1   gender            5043 non-null   object 
 2   SeniorCitizen     5043 non-null   object 
 3   Partner           5043 non-null   object 
 4   Dependents        5043 non-null   object 
 5   tenure            5043 non-null   int64  
 6   PhoneService      5043 non-null   object 
 7   MultipleLines     4774 non-null   object 
 8   InternetService   5043 non-null   object 
 9   OnlineSecurity    4392 non-null   object 
 10  OnlineBackup      4392 non-null   object 
 11  DeviceProtection  4392 non-null   object 
 12  TechSupport       4392 non-null   object 
 13  StreamingTV       4392 non-null   object 
 14  StreamingMovies   4392 non-null   object 
 15  Contract          5043 non-null   object 
 16  PaperlessBilling  5043 non-null   object

Из предоставленного вывода мы можем получить следующую информацию:

  • Размер набора данных: DataFrame состоит из 5043 записей (строк) с 21 столбцом.
  • Имена столбцов: DataFrame содержит несколько столбцов, в том числе «идентификатор клиента», «пол», «SeniorCitizen», «Партнер», «Иждивенцы», «должность», «PhoneService», «MultipleLines», «InternetService», «OnlineSecurity», «OnlineBackup», «DeviceProtection», «TechSupport», «StreamingTV», «StreamingMovies», «Contract» и «PaperlessBilling».
  • Типы данных. Типы данных столбцов различаются, включая объекты (строки) и int64 (целые числа).
  • Ненулевые значения: в столбцах «CustomerID», «Gender», «SeniorCitizen», «Partner», «Dependents», «Tenure», «PhoneService», «InternetService» и «Contract» отсутствуют пропущенные значения (не нулевой счетчик, равный общему количеству записей, 5043). Однако в других столбцах, таких как «MultipleLines», «OnlineSecurity», «OnlineBackup», «DeviceProtection», «TechSupport», «StreamingTV», «StreamingMovies» и «PaperlessBilling», отсутствуют значения (ненулевое количество меньше 5043). ).
  • Категориальные переменные: DataFrame включает категориальные переменные, такие как «пол», «SeniorCitizen», «Partner», «Dependents», «PhoneService», «MultipleLines», «InternetService», «OnlineSecurity», «OnlineBackup», «DeviceProtection», «Техническая поддержка», «Потоковое ТВ», «Потоковое кино», «Контракт» и «Безбумажный выставление счетов». Эти переменные, вероятно, представляют разные категории или варианты для каждого клиента.
  • Числовая переменная: столбец «срок пребывания» представляет числовую переменную, указывающую количество месяцев, в течение которых клиент работал в компании.

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

Описание фрейма данных: использование метода .describe() для предварительного просмотра распределения, характера и уникальных значений в столбцах фрейма данных.

df_train.describe()

выход



      customerID  gender  SeniorCitizen Partner Dependents  tenure  \
0     5600-PDUJF    Male              0      No         No       6   
1     8292-TYSPY    Male              0      No         No      19   
2     0567-XRHCU  Female              0     Yes        Yes      69   
3     1867-BDVFH    Male              0     Yes        Yes      11   
4     2067-QYTCF  Female              0     Yes         No      64   
...          ...     ...            ...     ...        ...     ...   
2038  6840-RESVB    Male              0     Yes        Yes      24   
2039  2234-XADUH  Female              0     Yes        Yes      72   
2040  4801-JZAZL  Female              0     Yes        Yes      11   
2041  8361-LTMKD    Male              1     Yes         No       4   
2042  3186-AJIEK    Male              0      No         No      66   

     PhoneService     MultipleLines InternetService OnlineSecurity  ...  \
0             Yes                No             DSL             No  ...   
1             Yes                No             DSL             No  ...   
2              No  No phone service             DSL            Yes  ...   
3             Yes               Yes     Fiber optic             No  ...   
4             Yes               Yes     Fiber optic             No  ...   
...           ...               ...             ...            ...  ...   
2038          Yes               Yes             DSL            Yes  ...   
2039          Yes               Yes     Fiber optic             No  ...   
2040           No  No phone service             DSL            Yes  ...   
2041          Yes               Yes     Fiber optic             No  ...   
2042          Yes                No     Fiber optic            Yes  ...   

     DeviceProtection TechSupport StreamingTV StreamingMovies        Contract  \
0                  No         Yes          No              No  Month-to-month   
1                 Yes         Yes          No              No  Month-to-month   
2                 Yes          No          No             Yes        Two year   
3                  No          No          No              No  Month-to-month   
4                 Yes         Yes         Yes             Yes  Month-to-month   
...               ...         ...         ...             ...             ...   
2038              Yes         Yes         Yes             Yes        One year   
2039              Yes          No         Yes             Yes        One year   
2040               No          No          No              No  Month-to-month   
2041               No          No          No              No  Month-to-month   
2042              Yes         Yes         Yes             Yes        Two year   

     PaperlessBilling              PaymentMethod MonthlyCharges  TotalCharges  \
0                 Yes    Credit card (automatic)          49.50         312.7   
1                 Yes    Credit card (automatic)          55.00        1046.5   
2                 Yes    Credit card (automatic)          43.95        2960.1   
3                 Yes           Electronic check          74.35         834.2   
4                 Yes           Electronic check         111.15        6953.4   
...               ...                        ...            ...           ...   
2038              Yes               Mailed check          84.80        1990.5   
2039              Yes    Credit card (automatic)         103.20        7362.9   
2040              Yes           Electronic check          29.60        346.45   
2041              Yes               Mailed check          74.40         306.6   
2042              Yes  Bank transfer (automatic)         105.65        6844.5   

     Churn  
0       No  
1      Yes  
2       No  
3      Yes  
4       No  
...    ...  
2038    No  
2039    No  
2040    No  
2041   Yes  
2042    No  

Из приведенного выше вывода мы можем сделать вывод, что 75% клиентов имеют срок владения менее 56 месяцев и среднюю ежемесячную плату в размере 65 долларов США. Следует пойти дальше, проанализировав, используя метод .describe для всех столбцов по отдельности, чтобы лучше понять данные.

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

df_train.isna().sum()

выход

customerID            0
gender                0
SeniorCitizen         0
Partner               0
Dependents            0
tenure                0
PhoneService          0
MultipleLines       269
InternetService       0
OnlineSecurity      651
OnlineBackup        651
DeviceProtection    651
TechSupport         651
StreamingTV         651
StreamingMovies     651
Contract              0
PaperlessBilling      0
PaymentMethod         0
MonthlyCharges        0
TotalCharges          8
Churn                 1
dtype: int64

мы видим, что в общей сложности 8 столбцов имеют пропущенные значения

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

# Univariate Analysis
# Numeric Columns
numeric_columns = ['tenure', 'MonthlyCharges', 'TotalCharges']
df_train[numeric_columns].hist(bins=30, figsize=(15, 10))
plt.suptitle('Univariate Analysis - Numeric Columns', y=0.92)
plt.show()

На основании приведенных выше гистограмм мы делаем следующие выводы. Распределение владения:

Гистограмма для столбца «должность» показывает, что распределение слегка смещено вправо, с пиком вокруг более низких значений. Это указывает на то, что у значительного числа клиентов относительно короткий срок пребывания в компании.

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

Распределение общих расходов: гистограмма для столбца «Общие расходы» показывает положительно асимметричное распределение с длинным хвостом в сторону более высоких значений. Это говорит о том, что существует группа клиентов с более высокими общими платежами, потенциально указывающая на долгосрочных или ценных клиентов.

одномерный анализ категориальных столбцов:

# Categorical Columns(Univariate)
categorical_columns = ['gender', 'SeniorCitizen', 'Partner', 'Dependents',
                       'PhoneService', 'MultipleLines', 'InternetService',
                       'OnlineSecurity', 'OnlineBackup', 'DeviceProtection',
                       'TechSupport', 'StreamingTV', 'StreamingMovies',
                       'Contract', 'PaperlessBilling', 'PaymentMethod', 'Churn']
# ploting visualisations
for column in categorical_columns:
    plt.figure(figsize=(8, 6))
    sns.countplot(x=column, data=df_train)
    plt.title(f'Univariate Analysis - {column}')
    plt.xticks(rotation=45)
    plt.show()

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

Двумерный анализ.Двумерный анализ – это статистический метод, используемый для анализа связи между двумя переменными. Он исследует, как изменения одной переменной влияют на другую переменную. В приведенном ниже коде двумерный анализ выполняется для категориальных переменных в наборе данных по отношению к переменной «Churn».

# Bivariate Analysis
for column in categorical_columns:
    if column != 'Churn':
        plt.figure(figsize=(10, 6))
        sns.countplot(x=column, hue='Churn', data=df_train)
        plt.title(f'Bivariate Analysis: {column} vs. Churn')
        plt.xlabel(column)
        plt.ylabel('Count')
        plt.legend(title='Churn', labels=['No', 'Yes'])
        plt.show()

Ниже приведен пример вывода кода

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

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

# Multivariate Analysis
# Numeric Columns
numeric_columns = ['tenure', 'MonthlyCharges', 'TotalCharges']
plt.figure(figsize=(10, 8))
sns.heatmap(df_train[numeric_columns].corr(), annot=True, cmap='coolwarm')
plt.title('Multivariate Analysis - Numeric Columns')
plt.show()

мы можем сделать вывод, что диагональный рисунок тепловой карты с коэффициентом корреляции, равным 1, предполагает, что существует сильная положительная линейная связь между «владением» и «ежемесячными платежами», а также между «ежемесячными платежами» и «общими платежами». Это означает, что клиенты с более длительным сроком владения, как правило, имеют более высокие ежемесячные платежи и более высокие общие платежи, в то время как клиенты с более коротким сроком пребывания имеют более низкие ежемесячные платежи и более низкие общие платежи.

ПРОВЕРКА ГИПОТЕЗ

Проверка гипотезы — это статистическая процедура, используемая для получения выводов или выводов о совокупности на основе выборочных данных. Он включает в себя формулирование нулевой гипотезы (H0) и альтернативной гипотезы (Ha) и использование статистических методов для определения того, подтверждают ли данные из данных отклонение нулевой гипотезы в пользу альтернативной гипотезы.

H0 – существенных различий в показателях оттока между клиентами-мужчинами и женщинами нет.

H1 – Есть ли существенная разница в показателях оттока клиентов-мужчин и женщин?

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

contingency_table = pd.crosstab(df_train['gender'], df_train['Churn'])
chi2, p_value, _, _ = chi2_contingency(contingency_table)

# Set the significance level
alpha = 0.05

# Print the results
print("Chi-Square Test of Independence - Gender vs. Churn")
print(f"Chi2 statistic: {chi2}")
print(f"P-value: {p_value}")

# Check the result based on the significance level
if p_value < alpha:
    print("There is a significant association between gender and churn.")
else:
    print("There is no significant association between gender and churn.")

выход

Chi-Square Test of Independence - Gender vs. Churn
Chi2 statistic: 0.021628520637713346
P-value: 0.8830796247912641
There is no significant association between gender and churn.

Статистика Chi2 — это мера расхождения между наблюдаемыми частотами и частотами, которые можно было бы ожидать, если бы две переменные (пол и отток) были независимыми. Меньшая статистика Chi2 указывает на меньшее несоответствие.

Наше p-значение (0,8) больше, чем обычно используемый уровень значимости 0,05, мы не можем отвергнуть нулевую гипотезу. Это означает, что недостаточно доказательств, чтобы предположить значительную связь между полом и оттоком. Таким образом, на основании имеющихся данных можно сделать вывод, что пол не оказывает существенного влияния на отток клиентов.

H0 : тип интернет-сервиса не влияет на отток клиентов.

H1. Влияет ли тип интернет-услуг на отток клиентов?

contingency_table = pd.crosstab(df_train['InternetService'], df_train['Churn'])
chi2, p_value, _, _ = chi2_contingency(contingency_table)

# Set the significance level
alpha = 0.05

# Print the results
print("Chi-Square Test of Independence - Internet Service vs. Churn")
print(f"Chi2 statistic: {chi2:.2f}")
print(f"P-value: {p_value:.2f}")

# Check the result based on the significance level
if p_value < alpha:
    print("There is a significant association between Internet Service and Churn.")
else:
    print("There is no significant association between Internet Service and Churn.")

выход

Chi-Square Test of Independence - Internet Service vs. Churn
Chi2 statistic: 562.27
P-value: 0.00
There is a significant association between Internet Service and Churn

Статистика chi2 измеряет степень связи между переменными (интернет-сервис и отток)

значение p чрезвычайно мало (0,00), значительно ниже обычного уровня значимости 0,05, мы отвергаем нулевую гипотезу. Это означает, что есть убедительные доказательства того, что существует значительная связь между Интернет-сервисом и оттоком. Результат указывает на то, что тип Интернет-услуги, которой пользуется клиент, вероятно, повлияет на его вероятность оттока.

H0: клиенты с более длительным сроком пребывания с большей вероятностью уйдут.

H1. Вероятность ухода клиентов с более длительным стажем меньше?

Тест гипотезы: T-test-Ttest — это статистический тест, используемый для определения того, существует ли значительная разница между средними значениями двух групп или популяций.

group1 = df_train[df_train['Churn'] == 'No']['tenure'].values
group2 = df_train[df_train['Churn'] == 'Yes']['tenure'].values

t_statistic, p_value = ttest_ind(group1, group2)

# Set the significance level
alpha = 0.05

# Print the results
print("Independent t-test - Tenure vs. Churn")
print(f"T-statistic: {t_statistic:.2f}")
print(f"P-value: {p_value:.2f}")

# Check the result based on the significance level
if p_value < alpha:
    print("There is a significant difference in tenure between churned and non-churned customers.")
else:
    print("There is no significant difference in tenure between churned and non-churned customers.")

выход

Independent t-test - Tenure vs. Churn
T-statistic: 26.59
P-value: 0.00
There is a significant difference in tenure between churned and non-churned customers.

Значение t-статистики равно 26,60. Это значение представляет собой величину разницы в среднем сроке пребывания ушедших и не ушедших клиентов.

Значение p равно 0,00. Это значение представляет собой вероятность получения наблюдаемой разницы в сроках пребывания между ушедших и не ушедших клиентов только случайно. В этом случае p-значение чрезвычайно мало, что указывает на убедительные доказательства против нулевой гипотезы (отсутствие различий).

H0 — способ оплаты не влияет на отток клиентов.

H1 – Влияет ли способ оплаты на отток клиентов?

contingency_table = pd.crosstab(df_train['PaymentMethod'], df_train['Churn'])
chi2, p_value, _, _ = chi2_contingency(contingency_table)

# Set the significance level
alpha = 0.05

# Print the results
print("Chi-Square Test of Independence - Payment Method vs. Churn")
print(f"Chi2 statistic: {chi2:.2f}")
print(f"P-value: {p_value:.2f}")

# Check the result based on the significance level
if p_value < alpha:
    print("There is a significant association between Payment Method and Churn.")
else:
    print("There is no significant association between Payment Method and Churn.")

выход

Chi-Square Test of Independence - Payment Method vs. Churn
Chi2 statistic: 435.18
P-value: 0.00
There is a significant association between Payment Method and Churn.

Статистика Chi2, равная 434,58, указывает на более сильную связь

P-значение (0,00) представляет собой вероятность случайного наблюдения связи между методом оплаты и оттоком.

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

Ответы на вопросы с помощью визуализаций

Вопрос 1. Есть ли существенная разница в показателях оттока клиентов-мужчин и женщин?

# Create a contingency table of gender and churn
contingency_table = pd.crosstab(df_train['gender'], df_train['Churn'])

# Calculate the churn rates by gender
churn_rates = contingency_table['Yes'] / contingency_table.sum(axis=1)

# Plot the churn rates
plt.figure(figsize=(8, 6))
sns.barplot(x=churn_rates.index, y=churn_rates.values)
plt.title('Churn Rates by Gender')
plt.xlabel('Gender')
plt.ylabel('Churn Rate')
plt.show()

сюжет

Коэффициент оттока женщин составляет примерно 0,25, а коэффициент оттока мужчин - примерно 0,23, это говорит о том, что существует небольшая разница в коэффициентах оттока между двумя полами. Однако разница относительно невелика.

Это означает, что в среднем показатель оттока клиентов-женщин немного выше, чем показатель оттока клиентов-мужчин, но разница несущественна. Это указывает на то, что пол сам по себе не может быть сильным предиктором оттока клиентов в этом наборе данных.

Вопрос 2. Влияет ли тип интернет-сервиса на отток клиентов

plt.figure(figsize=(8, 6))
sns.countplot(x='InternetService', hue='Churn', data=df_train)
plt.title('Churn by Internet Service')
plt.xlabel('Internet Service')
plt.ylabel('Count')
plt.show()

Результаты визуализации показывают, что клиенты с интернет-услугой DSL имеют наибольшее количество неотчужденных клиентов, количество которых составляет 1400. С другой стороны, количество ушедших клиентов для интернет-услуги DSL составляет 300.

Это говорит о том, что клиенты с интернет-услугами DSL менее склонны к оттоку по сравнению с другими типами интернет-услуг. Оптика, с другой стороны, имеет меньше клиентов, которые не ушли, и больше клиентов, которые ушли.

Таким образом, тип интернет-сервиса, по-видимому, влияет на отток клиентов, при этом интернет-сервис DSL демонстрирует более низкий уровень оттока по сравнению с другими типами.

Вопрос 3 – вероятность оттока клиентов с более длительным стажем работы меньше

# Calculate churn rate for different tenure groups
tenure_groups = df_train.groupby(pd.cut(df_train['tenure'], bins=[0, 12, 24, 36, 48, 60, float('inf')]))
churn_rate = tenure_groups['Churn'].value_counts(normalize=True).unstack()['Yes']

# Plot the churn rate
plt.figure(figsize=(10, 6))
churn_rate.plot(kind='bar')
plt.title('Churn Rate by Tenure')
plt.xlabel('Tenure Groups')
plt.ylabel('Churn Rate')
plt.xticks(rotation=45)
plt.show()

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

У клиентов со стажем работы от 24 до 36 месяцев коэффициент оттока ниже — 0,2. Это говорит о том, что клиенты, которые пользуются сервисом в течение умеренного периода времени, с меньшей вероятностью уйдут, чем клиенты с более коротким сроком пребывания.

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

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

Вопрос 4. Влияет ли способ оплаты на отток клиентов?

plt.figure(figsize=(10, 8))
sns.countplot(x='PaymentMethod', hue='Churn', data=df_train)
plt.title('Churn by Payment Method')
plt.xlabel('Payment Method')
plt.ylabel('Count')
plt.show()

Результаты визуализации показывают, что метод оплаты «Электронный чек» имеет наибольшее количество как неотчужденных, так и ушедших клиентов, примерно 900 неотчужденных и 750 отчужденных клиентов. С другой стороны, способы оплаты «Почтовый чек», «Банковский перевод (автоматический)» и «Кредитная карта (автоматический)» имеют относительно одинаковое количество клиентов — около 900, но их отток значительно ниже — примерно 200. .

Это говорит о том, что способ оплаты «Электронный чек» имеет более высокий уровень оттока по сравнению с другими способами оплаты. Клиенты, использующие электронные чеки в качестве способа оплаты, с большей вероятностью уйдут по сравнению с клиентами, которые используют другие способы оплаты, такие как почтовый чек, банковский перевод (автоматически) или кредитная карта (автоматически).

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

Обработка и проектирование функций

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

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

Отбрасывание отсутствующего значения в столбце оттока, поскольку оно единственное

df_train.dropna(subset=['Churn'], inplace=True)

Преобразование целевой переменной в двоичное числовое значение Да:1, Нет:0, поскольку модели машинного обучения работают с числовыми переменными

# Create a NumPy array to represent the target variable
target = np.where(df_train['Churn'] == 'Yes', 1, 0)

# Assign the new NumPy array to the 'Churn' column
df_train['Churn'] = target

# Verify the conversion
df_train['Churn'].unique 

Удалите столбец CustomerID, поскольку его релевантность ограничена.

df_train.drop("customerID", axis=1, inplace=True)

Замена отсутствующих значений в определенных столбцах

Обоснование кода заключается в замене отсутствующих значений в определенных столбцах на «Нет» при условии, что у соответствующего клиента нет интернет-услуги. Это связано с тем, что без интернет-сервиса определенные сервисы (например, онлайн-безопасность, защита устройства) не применимы или недоступны.

columns_to_replace = ["OnlineSecurity", "OnlineBackup", "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies"]
for column in columns_to_replace:
    df_train[column] = np.where((df_train["InternetService"] == "No") & (df_train[column].isnull()), "No internet service", df_train[column])

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

categorical = ['gender','SeniorCitizen','Partner','Dependents','PhoneService','MultipleLines', 
               'InternetService','OnlineSecurity','OnlineBackup','DeviceProtection','TechSupport',
               'StreamingTV','StreamingMovies', 'Contract','PaperlessBilling','PaymentMethod']
numerical = ['tenure', 'MonthlyCharges', 'TotalCharges']

Разделение набора данных

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

X = df_train.drop(columns="Churn") создает новый фрейм данных X, удаляя столбец "Отток" из исходного df_train. Это будет включать все столбцы, кроме столбца «Отток», представляющего функции или независимые переменные.

y = df_train["Churn"].values создает массив NumPy y, содержащий значения столбца "Отток" из исходного df_train. Это представляет целевую переменную или зависимую переменную, которую мы хотим предсказать.

#creating dataframe x and y
X = df_train.drop(columns = "Churn")
y = df_train["Churn"].values

#splittin the y and x datasets to both train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 4, stratify =y)

В приведенном выше коде мы используем функцию train_test_split из библиотеки scikit-learn, чтобы разделить функции (X) и целевую переменную (y) на наборы для обучения и тестирования.

  • X: функции или независимые переменные.
  • y: Целевая переменная или зависимая переменная.
  • test_size: доля данных, выделяемых для тестового набора. В данном случае установлено значение 0,2, что означает, что 20% данных будут использоваться для тестирования, а остальные 80% — для обучения.
  • random_state: начальное значение, используемое генератором случайных чисел для воспроизводимости. Установка для него определенного значения (например, 4) гарантирует, что при каждом запуске кода будет получаться одно и то же случайное разделение.
  • stratify: для этого параметра задано значение y, что обеспечивает стратификацию разделения на основе значений y. Это помогает поддерживать пропорцию различных классов в целевой переменной в наборах для обучения и тестирования. Это особенно полезно при работе с несбалансированными наборами данных, где классы представлены неравномерно.

Вставить отсутствующие значения

Это фаза заполнения пропущенных значений, процесс, известный как вменение.

вмените пропущенные значения в режиме для категориальных признаков, используя класс scikit-learn SimpleImputer. В этой строке вы создаете экземпляр класса SimpleImputer и указываете стратегию вменения как 'most_frequent'. Эта стратегия указывает, что отсутствующие значения должны быть заменены режимом (наиболее часто встречающимся значением) столбца.

Здесь мы применяем вменение к обучающему набору. X_train[categorical] представляет подмножество обучающего набора, которое содержит только категориальные признаки. Метод fit_transform из SimpleImputer используется для подгонки импутера к обучающим данным (X_train[categorical]) и одновременного выполнения импутирования. Он заменяет отсутствующие значения в категориальных функциях режимом и возвращает вмененный набор данных.

#Impute missing values with the mode for categorical features
categorical_imputer = SimpleImputer(strategy='most_frequent')
X_train_imputed = categorical_imputer.fit_transform(X_train[categorical])
X_test_imputed = categorical_imputer.transform(X_test[categorical])
#Impute missing values with the mode for categorical features
categorical_imputer = SimpleImputer(strategy='most_frequent')
X_train_imputed = categorical_imputer.fit_transform(X_train[categorical])
X_test_imputed = categorical_imputer.transform(X_test[categorical])

Кодирование функций

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

Существует несколько распространенных методов кодирования признаков, в зависимости от характера данных и конкретных требований задачи:

Однократное кодирование. Однократное кодирование используется для категориальных переменных без внутренней порядковой связи между категориями. Каждая категория представлена ​​в виде бинарного признака, где значение 1 указывает на наличие категории, а 0 указывает на ее отсутствие. Этот метод создает новые двоичные столбцы для каждой категории, эффективно расширяя пространство признаков.

Кодировка метки. Кодировка метки используется, когда между категориями существует порядковая связь. Каждой категории присваивается уникальная целочисленная метка. Например, в порядковой переменной, такой как «Низкий», «Средний» и «Высокий», категории могут быть закодированы как 0, 1 и 2 соответственно.

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

# Apply one-hot encoding on the training set
encoder = OneHotEncoder(drop='if_binary')
X_train_encoded = pd.DataFrame(encoder.fit_transform(X_train[categorical]).toarray(),
                               columns=encoder.get_feature_names_out(categorical),
                               index=X_train.index)

# Apply the same encoding on the testing set
X_test_encoded = pd.DataFrame(encoder.transform(X_test[categorical]).toarray(),
                              columns=encoder.get_feature_names_out(categorical),
                              index=X_test.index)

Масштабирование функций

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

Минимально-максимальное масштабирование. Масштабирование по минимально-максимальному значению, также известное как нормализация, масштабирует объекты в определенном диапазоне, обычно от 0 до 1. При этом вычитается минимальное значение функцию и делит ее на диапазон (максимальное значение минус минимальное значение). Результирующий преобразованный объект будет иметь значения от 0 до 1. Мин.-макс. масштабирование сохраняет исходное распределение объекта. Другим методом является стандартизация (нормализация Z-показателя).

# Create an instance of the StandardScaler
scaler = StandardScaler()

# Fit and transform the numeric variables in the training set
X_train_encoded[numerical] = scaler.fit_transform(X_train[numerical])

# Transform the numeric variables in the testing set using the fitted scaler
X_test_encoded[numerical] = scaler.transform(X_test[numerical])
# Concatenate the encoded & scaled training and testing sets
X_encoded = pd.concat([X_train_encoded, X_test_encoded], axis=0)
# Reset the index of X_train
X_train.reset_index(drop=True, inplace=True)

# Create a new DataFrame with the target variable and the "MonthlyCharges_TotalCharges_Ratio" column
correlation_df = pd.concat([X_train['MonthlyCharges_TotalCharges_Ratio'], pd.Series(y_train, name='Churn')], axis=1)

# Calculate the correlation matrix
correlation_matrix = correlation_df.corr()

# Create a heatmap
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('Correlation Heatmap: MonthlyCharges_TotalCharges_Ratio vs Churn')
plt.show()

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

Балансировка набора поездов

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

# Convert y_train and y_test to Pandas Series
y_train_series = pd.Series(y_train)
y_test_series = pd.Series(y_test)

# Count the number of samples in each class in the training set
train_class_counts = y_train_series.value_counts()

# Count the number of samples in each class in the testing set
test_class_counts = y_test_series.value_counts()

# Plot the class distribution
plt.figure(figsize=(8, 6))
plt.bar(train_class_counts.index, train_class_counts.values, color='blue', label='Train')
plt.bar(test_class_counts.index, test_class_counts.values, color='orange', label='Test')
plt.xlabel('Class')
plt.ylabel('Count')
plt.title('Class Distribution')
plt.legend()
plt.show()

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

Распределение экземпляров с оттоком и без оттока в обучающем и тестовом наборах.

train_churn_count = pd.Series(y_train).value_counts()
test_churn_count = pd.Series(y_test).value_counts()

print("Churn count in y_train:")
print(train_churn_count)

print("\nChurn count in y_test:")
print(test_churn_count) 

выход

Churn count in y_train:
0    2964
1    1069
dtype: int64

Churn count in y_test:
0    742
1    267
dtype: int64

Учебный набор: класс большинства — «0» (без оттока) с 2964 экземплярами, а класс меньшинства — «1» (отток) с 1069 экземплярами. Это указывает на то, что обучающий набор несбалансирован, и в нем значительно больше экземпляров без оттока по сравнению с экземплярами оттока.

Тестовый набор: аналогично, класс большинства — «0» (без оттока) с 742 экземплярами, а класс меньшинства — «1» (отток) с 267 экземплярами. Дисбаланс классов также наблюдается в тестовой выборке.

Теперь мы применяем алгоритм SMOTETomek для балансировки обучающих данных. SMOTETomek представляет собой комбинацию алгоритмов SMOTE (Synthetic Minority Over-sampling Technique) и алгоритмов Tomek Links, которые одновременно передискретизируют класс меньшинства (отток) и занижают выборку класса большинства (не отток).

# Create an instance of SMOTETomek
smote_tomek = SMOTETomek()

# Apply SMOTETomek to the training data
X_train_balanced, y_train_balanced = smote_tomek.fit_resample(X_train_encoded, y_train)

# Check the count of each class in the balanced training data
balanced_class_count = pd.Series(y_train_balanced).value_counts()
print("Class count in the balanced training data:")
print(balanced_class_countcode

Приведенный выше фрагмент кода создает экземпляр класса SMOTETomek: smote_tomek = SMOTETomek().

Алгоритм SMOTETomek затем применяется к обучающим данным с использованием метода fit_resample: X_train_balanced, y_train_balanced = smote_tomek.fit_resample(X_train_encoded, y_train). Это передискретизирует обучающие данные для создания сбалансированной версии с одинаковым представлением классов оттока и неоттока.

Обучение моделей/Оценка/Сравнение моделей

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

Оцените модель: оцените производительность обученной модели, используя данные проверки или перекрестную проверку. Рассчитайте соответствующие показатели, такие как точность, воспроизводимость, полнота, оценка F1 или среднеквадратическая ошибка, в зависимости от типа задачи. Оцените, насколько хорошо модель обобщает невидимые данные, и при необходимости рассмотрите возможность корректировки гиперпараметров или структуры модели.

Приведенный ниже код определяет функцию calculate_metrics, которая вычисляет показатели производительности для задачи двоичной классификации. В настоящее время он вычисляет оценку F1 на основе истинных меток (y_true) и предсказанных меток (y_pred).

# Define the calculate_metrics function
def calculate_metrics(y_true, y_pred):
    metrics = {}
    metrics['f1_score'] = f1_score(y_true, y_pred)
    return metrics

Затем мы инициализируем модели, мы будем использовать следующие модели: логистическая регрессия, дерево решений, случайный лес, повышение градиента, AdaBoost, SVM, KNN, Naive Bayes, XGBoost, LightGBM, CatBoost модели будут построены и оценены с данными о дисбалансе, создать таблицу лидеров, которая покажет метрическую производительность моделей

`leaderboard_imbalanced = {}

for model, name in zip(models, model_names):
    model.fit(X_train_encoded, y_train)
    y_pred = model.predict(X_test_encoded)
    metrics = calculate_metrics(y_test, y_pred)
    leaderboard_imbalanced[name] = metrics
    
    # Print the classification report
    print(f"Classification Report for {name}:")
    print(classification_report(y_test, y_pred, labels=[0, 1], target_names=['No', 'Yes']))
    print()

# Create a DataFrame from the leaderboard dictionary
leaderboard_df = pd.DataFrame(leaderboard_imbalanced).transpose()

# Format the F1-score column to display with two decimal places
leaderboard_df['Imbalanced Data F1-score'] = leaderboard_df['f1_score'].map('{:.2f}'.format)

# Print the leaderboard DataFrame
print("Leaderboard: Imbalance Data")
leaderboard_df.drop('f1_score', axis=1, inplace=True)
leaderboard_df

когда мы вызываем кадр данных таблицы лидеров, мы получаем вывод, показывающий результаты оценок f1 моделей следующим образом. Эти результаты имеют несбалансированные данные.

 Imbalanced Data F1-score
Logistic Regression 0.60
Decision Tree 0.59
Random Forest 0.54
Gradient Boosting 0.60
AdaBoost 0.56
SVM 0.58
KNN 0.54
Naive Bayes 0.59
XGBoost 0.59
LightGBM 0.60
CatBoost 

Как и в случае с несбалансированными данными, мы строим и оцениваем модели на сбалансированных обучающих данных. Затем мы создаем таблицу лидеров производительности модели на основе метрики F1-score и, наконец, печатаем DataFrame таблицы лидеров.

leaderboard_balanced = {}

for model, name in zip(models, model_names):
    model.fit(X_train_balanced, y_train_balanced)
    y_pred = model.predict(X_test_encoded)
    metrics = calculate_metrics(y_test, y_pred)
    leaderboard_balanced[name] = metrics
    
    # Print the classification report
    print(f"Classification Report for {name}:")
    print(classification_report(y_test, y_pred, labels=[0, 1], target_names=['No', 'Yes']))
    print()

# Create a DataFrame from the leaderboard dictionary
leaderboard_df1 = pd.DataFrame(leaderboard_balanced).transpose()

 #Format the F1-score column to display with two decimal places
leaderboard_df1['Balanced Data F1-score'] = leaderboard_df1['f1_score'].map('{:.2f}'.format)

# Print the leaderboard DataFrame
print("Leaderboard: Balanced Data")
leaderboard_df1.drop('f1_score', axis=1, inplace=True)
leaderboard_df1

со сбалансированными данными мы получаем следующие результаты

 Balanced Data F1-score
Logistic Regression 0.63
Decision Tree 0.64
Random Forest 0.63
Gradient Boosting 0.64
AdaBoost 0.63
SVM 0.62
KNN 0.55
Naive Bayes 0.59
XGBoost 0.63
LightGBM 0.59
CatBoost 

Мы видим, что Gradient Boosting имеет самый высокий балл fi, что означает, что у него более правильный прогноз, чем у других моделей.

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

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

В задачах бинарной классификации матрица путаницы представляет собой матрицу 2 на 2, состоящую из 4 элементов:

  • TP (True Positive): количество пациентов с проблемами позвоночника, которые правильно классифицированы как больные.
  • TN (True Negative): количество пациентов без патологий, которые правильно классифицированы как здоровые.
  • FP (ложноположительный результат): количество здоровых пациентов, ошибочно классифицированных как больные.
  • FN (False Negative): количество пациентов с заболеваниями позвоночника, ошибочно классифицированных как здоровые.

Теперь, когда модель обучена, пришло время оценить ее производительность с помощью тестового набора. Сначала мы используем предыдущую модель (классификатор повышения градиента с лучшими гиперпараметрами), чтобы предсказать метки классов тестовых данных. (методом predict). Затем мы строим матрицу путаницы, используя функцию confusion_matrix из пакета sklearn.metrics, чтобы проверить, какие наблюдения были правильно классифицированы. Результатом является массив NumPy, в котором строки представляют истинные значения, а столбцы — предсказанные классы.

# Iterate over each model and its corresponding name in the leaderboard
for model, name in zip(models, model_names):
    # Fit the model on the balanced training data
    model.fit(X_train_balanced, y_train_balanced)
    
    # Predict the labels for the test data
    y_pred = model.predict(X_test_encoded)
    
    # Compute the confusion matrix
    cm = confusion_matrix(y_test, y_pred)
    
    # Create a heatmap for the confusion matrix
    plt.figure(figsize=(8, 6))
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', cbar=False)
    plt.title(f"Confusion Matrix for {name}")
    plt.xlabel("Predicted Churn")
    plt.ylabel("Actual Churn")
    plt.show()
    
    # Print the confusion matrix
    print(f"Confusion Matrix for {name}:")
    print(cm)
    print()

Настройка гиперпараметров

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

Для настройки гиперпараметров нам нужно снова разделить обучающие данные на набор для обучения и набор для тестирования гиперпараметров (часто называемый проверочным набором). Очень часто используется k-fold перекрестная проверка для настройки гиперпараметров. Обучающий набор снова делится на k выборок одинакового размера, 1 выборка используется для тестирования, а оставшиеся k-1 выборки используются для обучения модели, повторяя процесс k раз. Затем k показателей оценки (в данном случае точность) усредняются, чтобы получить единую оценку.

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

Настройка гиперпараметров с перекрестной проверкой — изображение создано автором

Существует несколько методов поиска лучших гиперпараметров для модели. Наиболее популярными методами являются (1) поиск по сетке, (2) случайный поиск и (3) байесовская оптимизация. Поиск по сетке проверяет все комбинации гиперпараметров и выбирает наиболее эффективную. Это очень трудоемкий метод, особенно когда количество гиперпараметров и значений, которые нужно попробовать, очень велико.

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

Поиск по сетке против случайного поиска — изображение создано автором

Мы можем реализовать случайный поиск в Scikit-learn, используя класс RandomSearchCV из пакета sklearn.model_selection.

Прежде всего, мы указываем сетку значений гиперпараметров с помощью словаря (grid_parameters), где ключи представляют гиперпараметры и значения — это набор параметров, которые мы хотим оценить. Затем мы определяем объект RandomizedSearchCV для пробы различных случайных комбинаций из этой сетки. Количество выбранных комбинаций гиперпараметров определяется параметром n_iter. Естественно, увеличение n_iter в большинстве случаев приведет к более точным результатам, поскольку выбирается больше комбинаций; однако во многих случаях улучшение производительности не будет значительным.

# Define the models and their respective parameter grids
models = {
    'AdaBoost': AdaBoostClassifier(random_state=4),
    'Logistic Regression': LogisticRegression(random_state=4),
    'Random Forest' : RandomForestClassifier(random_state=4),
    'Gradient Boosting' : GradientBoostingClassifier(random_state=4)
}

leaderboard = {}
for name, model in models.items():
    # Get the available parameters for the model
    available_params = model.get_params()
    print(f"Available parameters for {name}: {available_params}\n")

# Perform hyperparameter tuning and store the best-tuned models
leaderboard = {}

настройка с использованием GridSearchCV и установка уровня детализации для печати прогресса

for name, model in models.items():
    # Define the selected parameter values for the model
    
    param_selections = {
    'AdaBoost': {'n_estimators': [100, 150, 200, 250, 300], 'learning_rate': [0.1, 0.05, 0.01, 0.001]},
    'Logistic Regression': {'C': [0.1, 1, 10, 100, 1000], 'solver': ['liblinear', 'lbfgs', 'newton-cg', 'sag', 'saga']},
    'Random Forest':  {'n_estimators': [50, 100, 150, 200, 300, 400, 500], 'max_depth': [5, 10, 20]},
    'Gradient Boosting': {'n_estimators': [100, 150, 200, 250, 300], 'learning_rate': [0.1, 0.05, 0.01, 0.001], 'max_depth': [3, 5, 7]}
     }
    
     #Set the verbosity level for printing progress
    verbose = 3 if name == 'Logistic Regression' else 0
    
    # Get the selected parameter values for the model
    param_grid = param_selections[name]
    
    # Perform hyperparameter tuning using GridSearchCV
    grid_search = GridSearchCV(model, param_grid, scoring='f1', cv=5, verbose=verbose, refit=True)
    grid_search.fit(X_train_balanced, y_train_balanced)
    
    # Get the best model and its parameters
    best_model = grid_search.best_estimator_
    best_params = grid_search.best_params_
    print(f"Best parameters for {name}: {best_params}\n")
    
    
     # Predict using the best model
    y_pred = best_model.predict(X_test_encoded)
    f1 = f1_score(y_test, y_pred)
    f1_rounded = round(f1, 2)
    leaderboard[name] = {'Tuned F1-score': f1}

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

`# Filter leaderboard for selected models
selected_models = ['Gradient Boosting','Random Forest', 'Logistic Regression', 'AdaBoost']
filtered_df = leaderboard_df.loc[selected_models]

filtered_df1 = leaderboard_df1.loc[selected_models]

# Filter leaderboard_df2 for selected models
filtered_df2 = leaderboard_df2.loc[selected_models]

# Concatenate the filtered DataFrames
combined_df = pd.concat([filtered_df, filtered_df1, filtered_df2], axis=1)

# Print the combined DataFrame
combined_df

эти наши результаты

 Imbalanced Data F1-score Balanced Data F1-score Tuned F1-score
Gradient Boosting 0.60      0.64                     0.64
Random Forest 0.54          0.63                     0.61
Logistic Regression 0.60    0.63                     0.63
AdaBoost 0.56               0.63                     0.63

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

Делаем выводы — Резюме

В этом посте мы рассмотрели полный комплексный проект машинного обучения с использованием набора данных Telco client Churn. Мы начали с очистки данных и их анализа с визуализацией. Затем, чтобы иметь возможность построить модель машинного обучения, мы преобразовали категориальные данные в числовые переменные (разработка признаков). После преобразования данных мы попробовали 6 различных алгоритмов машинного обучения с параметрами по умолчанию. Наконец, мы настроили гиперпараметры лучшей модели производительности для оптимизации модели, получив точность почти 64 %.

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