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

Это число не уникально: согласно исследованию, проведенному D-edge Hospitality Solutions в 2018 году, почти 40% бронирований отелей по всему миру отменяются. Оставляя менеджеров отелей с огромными альтернативными издержками.

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

Но что, если бы можно было предсказать, какие гости, скорее всего, отменят бронирование, и соответствующим образом скорректировать ставку перебронирования? Это было бы здорово, не так ли? К счастью для вас, это то, что мы собираемся сделать сегодня, используя магию машинного обучения в Python.

Прежде всего, мы собираемся импортировать наши библиотеки машинного обучения и (ранее очищенный) набор данных:

import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from yellowbrick.classifier import ConfusionMatrix
from sklearn.metrics import classification_report
from sklearn.dummy import DummyClassifier
pd.read_csv('cleaned_csv'

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

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

#defining categorical variables:
df_cat = df[['hotel','meal','market_segment','distribution_channel',\
'reserved_room_type','assigned_room_type','deposit_type',\
            'customer_type','reservation_status']]
#defining numeric variables:
df_num = 
df[['lead_time','adults','children','babies',\
'previous_cancellations','previous_bookings_not_canceled',\             'booking_changes','days_in_waiting_list',\
'required_car_parking_spaces','total_of_special_requests']]
#Dummy encoding categorical data:
df_dummies = pd.get_dummies(df_cat,drop_first=True)
#Scaling numeric data:
ss = StandardScaler()
df_num_scaled = pd.DataFrame(ss.fit_transform(df_num), columns = ['lead_time','adults','children','babies','previous_cancellations',\                                                             'previous_bookings_not_canceled','booking_changes',\
'days_in_waiting_list',\                                                          'required_car_parking_spaces','total_of_special_requests'])
#concatenating the two dataframes:
df_final = pd.concat([df_num_scaled,df_dummies,df['is_canceled']],axis=1)
#dropping missing values:
df_final = df_final.dropna()

Мы хотим разделить данные на обучающий набор и тестовый набор, чтобы мы могли проверить нашу модель на внешнюю достоверность:

X = df_sample.drop(columns=['is_canceled'])
y = df_sample['is_canceled']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

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

#Fitting a Dummy Model:
dummy = DummyClassifier(strategy='most_frequent')
dummy.fit(X_train, y_train)
dummy.score(X_test, y_test)

Фиктивная модель возвращает оценку 0,6355, что соответствует результатам исследования, проведенного D-edge Hospitality Solutions.

Теперь мы собираемся использовать модель логистической регрессии в качестве классификатора:

logreg = LogisticRegression()
logreg.fit(X_train,y_train)
logreg.score(X_train,y_train)

Модель логистической регрессии возвращает оценку 1,0.

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

Скорее всего, есть переменная, которая идеально коррелирует с целевой переменной, которая вызывает это, и, конечно же, после проверки регрессора «reservation_status» мы можем увидеть:

Поэтому мы должны удалить этот столбец из набора данных, чтобы удалить этот источник «утечки» из данных. Мы снова запускаем логистическую модель без этого столбца и получаем гораздо более разумную оценку 0,812.

Давайте посмотрим на новую матрицу путаницы:

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