Пошаговый рецепт Python.

Объяснение перекрестной проверки

Перекрестная проверка - это метод, позволяющий оценить производительность модели с меньшей дисперсией, чем при разбиении одного набора «поезд-тест». Он работает, разбивая набор данных на k частей (т.е. k = 5, k = 10). Каждый раз, когда мы разделяем данные, мы называем действие «складкой». Модель обучается на k-1 складках с одной отведенной назад и тестируется на удерживаемой задней части. Каждый сгиб должен быть как можно ближе к одному и тому же размеру записи. После выполнения перекрестной проверки вы получите k различных оценок производительности, которые мы суммируем, используя среднее значение и стандартное отклонение.

Предположим, у нас есть набор данных (всего n = 5000 записей), разделенный на k = 5 частей (каждая часть n = 1000). Мы помечаем части A, B, C, D и E. Модель будет обучена 5 раз. Каждый раз 4 (K-1) складки будут включены в тренировочную группу, а 5-я складка будет в тестовой группе. Группа тестирования меняется каждый раз при обучении модели. Пример модели перекрестной проверки k = 5:

  • Тренировка 1: тренировочные складки = A, B, C, D, а E - тестовая складка.
  • Тренировка 2: тренировочные складки = B, C, D, E, а A - тестовая складка.
  • Тренировка 3: тренировочные складки = C, D, E, A, в то время как B - тестовая складка.
  • Тренировка 4: тренировочные складки = D, E, A, B, в то время как C - тестовая складка.
  • Тренировка 5: тренировочные складки = E, A, B, C, а D - тестовая складка.

Результатом является более надежная оценка производительности модели на новых данных. Это более точно, потому что модель обучается и оценивается несколько раз на разных данных. Выбор k должен позволять размеру каждого тестового раздела быть достаточно большим, чтобы быть разумным образцом проблемы, в то же время позволяя достаточно повторений оценки «поезд-тест», чтобы обеспечить справедливую оценку производительности модели на невидимых данных. Для многих наборов данных с тысячами или десятками тысяч записей обычно используются значения k 3, 5 и 10.

Пошаговое руководство по Python

# Load the required libraries
import numpy as np
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report

Исходный набор данных находится на www.ibm.com.

# Load the data file. Add the correct directory path to reach the 
# file on your computer or network.
df=pd.read_csv(r'WA_Fn-UseC_-Telco-Customer-Churn.csv')

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

# Organize dataframe. Display the first five rows and column titles.
pd.set_option('display.max_columns', None) # Display all columns
df.head()

Очистка данных

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

df.columns.values

df.dtypes

К счастью, мы не пропустили этот шаг. Мы обнаруживаем, что столбец TotalCharges отображается как объект. Чтобы мы могли с ним работать, оно должно быть целым числом. Мы можем исправить это, преобразовав его в число. Кроме того, в это время я буду искать недостающие значения.

# Converting Total Charges to a numerical data type. Currently in dataframe as an object.
df.TotalCharges = pd.to_numeric(df.TotalCharges, errors='coerce')
df.isnull().sum()  # Count the number of missing values

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

Затем в этом блоке кода нам нужно преобразовать наши переменные ответа и предиктора в пригодные для использования форматы. Churn - это наша переменная ответа, и мы преобразуем ее из объекта в целое число. Мы присваиваем каждому да = 1 и нет = 0. Наконец, мы должны преобразовать категориальные переменные-предикторы в (числовые) фиктивные переменные. Затем еще раз посмотрим на заголовок.

# Removing missing values
df.dropna(inplace = True)
# Remove customer IDs from the data set
df2 = df.iloc[:,1:]
# Converting the predictor variable into a binary numeric variable
df2['Churn'].replace(to_replace='Yes', value=1, inplace=True)
df2['Churn'].replace(to_replace='No',  value=0, inplace=True)
# Convert all the categorical variables into dummy variables
df_dummies = pd.get_dummies(df2)
df_dummies.head()

Этот заголовок сильно отличается от предыдущего. Все объекты преобразованы в 0 и 1. Теперь данные готовы для логистической регрессии.

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

Первым шагом в логистической регрессии является присвоение нашим переменным ответа (Y) и предиктора (x). В этой модели отток - наша единственная переменная ответа, а все остальные переменные будут переменными-предикторами.

# assign X to all the independent (predictor) variables, assign Y to the dependent (response) variable
X = df_dummies[['SeniorCitizen','tenure','MonthlyCharges','TotalCharges','gender_Female','gender_Male','Partner_No','Partner_Yes','Dependents_No','Dependents_Yes','PhoneService_No','PhoneService_Yes','MultipleLines_No','MultipleLines_No phone service','MultipleLines_Yes','InternetService_DSL','InternetService_Fiber optic','InternetService_No','OnlineSecurity_No','OnlineSecurity_No internet service','OnlineSecurity_Yes','OnlineBackup_No','OnlineBackup_No internet service','OnlineBackup_Yes','DeviceProtection_No','DeviceProtection_No internet service','DeviceProtection_Yes','TechSupport_No','TechSupport_No internet service','TechSupport_Yes','StreamingTV_No','StreamingTV_No internet service','StreamingTV_Yes','StreamingMovies_No','StreamingMovies_No internet service','StreamingMovies_Yes','Contract_Month-to-month','Contract_One year','Contract_Two year','PaperlessBilling_No','PaperlessBilling_Yes','PaymentMethod_Bank transfer (automatic)','PaymentMethod_Credit card (automatic)','PaymentMethod_Electronic check','PaymentMethod_Mailed check' ]]
Y = df_dummies['Churn']

После этого выполняется k-кратная логистическая регрессия с перекрестной проверкой.

# 5 folds selected
kfold = KFold(n_splits=5, random_state=0, shuffle=True)
model = LogisticRegression(solver='liblinear')
results = cross_val_score(model, X, Y, cv=kfold)
# Output the accuracy. Calculate the mean and std across all folds. 
print("Accuracy: %.3f%% (%.3f%%)" % (results.mean()*100.0, results.std()*100.0))

Это относится к точности классификации, то есть количеству правильных прогнозов в процентах от всех сделанных прогнозов. Наша модель дала точность 80,333% (среднее значение) со стандартным отклонением 1,080%. При просмотре базового набора данных я обнаружил, что примерно 26% клиентов компании уходили каждый период, в то время как 74% оставались клиентами (это было предоставлено в виде примечания к файлу данных).

Помимо указания размера разделения (k = 5), мы также указываем случайное начальное число (random_state = 0). Поскольку разделение данных является случайным, мы хотим обеспечить воспроизводимость результатов. Указав случайное начальное число, мы гарантируем, что каждый раз при запуске кода мы получаем одни и те же случайные числа и, в свою очередь, одно и то же разделение данных. Это важно, если мы хотим сравнить этот результат с оценкой точности другой модели. Чтобы гарантировать, что сравнение проводилось по принципу «яблоки против яблок», мы должны убедиться, что они обучены и протестированы на абсолютно одинаковых данных.

Интерпретация результатов модели

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

# Construct a confusion matrix
test_size = 0.33
seed = 0
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=test_size,
random_state=seed)
model = LogisticRegression(solver='liblinear')
model.fit(X_train, Y_train)
predicted = model.predict(X_test)
matrix = confusion_matrix(Y_test, predicted)
print(matrix)

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

#transform confusion matrix into array
#the matrix is stored in a vaiable called confmtrx
confmtrx = np.array(matrix)
#Create DataFrame from confmtrx array 
#rows for test: Churn, No_Churn designation as index 
#columns for preds: Pred_Churn, Pred_NoChurn as column
pd.DataFrame(confmtrx, index=['No_Churn','Churn'],
columns=['Predicted_No_Churn', 'Predicted_Churn', ])

Так намного лучше. Эта диаграмма позволяет нам более четко понимать квадранты. Мы видим, что модель предсказывала «отсутствие оттока» 1799 раз (1522 + 277). Он был правильным 1522 раза и неправильным 277 раз (85% правильных), когда предсказывал «отсутствие оттока». Модель предсказала «отток» 522 раза (178 + 344). Когда прогнозировался «отток», это было правильным 344 раза и неверным 178 раз (66% правильных). Теперь, помимо 80%, у нас есть 85% и 66%. Что правильно? К счастью, мы можем создать отчет о классификации, который поможет нам во всем разобраться.

# Create a classification report. Use the same test size and same 
# seed number before. 
test_size = 0.33
seed = 0
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=test_size,
random_state=seed)
model = LogisticRegression(solver='liblinear')
model.fit(X_train, Y_train)
predicted = model.predict(X_test)
report = classification_report(Y_test, predicted)
print(report)

На скриншоте выше показан отчет о классификации. Есть четыре статистических столбца: точность, отзыв, оценка f1 и поддержка. Точность относится к тому, какой процент наших прогнозов оказался верным. Отсюда и возникли 85% и 66%. Среднее макроэкономическое значение рассчитывается как (0,85 + 0,66) / 2. Модель использует большую точность, чем два десятичных знака, и округляет до двух десятичных знаков. В итоге получаем 0,80 = (1700/2321) *. 85 + (621/2321) *. 66.

Напоминание - это процент положительных (или отрицательных) случаев, которые модель смогла обнаружить. В этом сценарии (1522/1700) = 0,90 и (344/621) = 0,55. Макро-среднее и средневзвешенное значение вычисляются с использованием тех же методов, которые показаны для точности.

F1-оценка - это взвешенное гармоническое среднее значение точности и запоминания, где наилучшая возможная оценка - 1,0, а наихудшая - 0,0. Считается, что для сравнения моделей лучше использовать средневзвешенную оценку F1, а не глобальную оценку точности. В этой модели оба значения равны 0,80, поэтому нет никакой разницы между глобальной точностью и взвешенной F1-оценкой.

Столбец поддержки предоставляет пользователю количество наблюдений в каждой строке и столбце.

Резюме

Модель, использующая k-кратную перекрестную проверку (k = 5), показала точность 80,333% со стандартным отклонением 1,080%. Модель отчета о матрице путаницы / классификации сообщила, что средневзвешенный балл F1 = 80% и глобальный балл точности = 80%. Модель k-кратной перекрестной проверки была почти идентична результатам модели отчета о матрице неточностей / классификации.

Пожалуйста, попробуйте эту k-кратную перекрестную проверку и дайте мне знать, если у вас возникнут вопросы или возникнут проблемы.

Больше контента на plainenglish.io