Эта задача связана с прогнозированием годовой доступности различных отелей на основе определенных характеристик, чтобы компания могла принять решение о сотрудничестве с отелем в отношении средств размещения.
Если вы хотите попрактиковаться, данные и полный код для справки можно найти по адресу: https://github.com/negiadventures/predicting_hotel_availability.git.
Описание данных
Обработка данных и визуализация
data = pd.read_csv("train.csv")
data.head()
data.describe()
# Checking data types for each column
data.dtypes '''
id int64 region object latitude float64 longitude float64 accommodation_type object cost int64 minimum_nights int64 number_of_reviews int64 reviews_per_month float64 owner_id int64 owned_hotels int64 yearly_availability int64 dtype: object
'''# Checking if any column have nulls data.isnull().sum(axis=0)
''' id 0 region 0 latitude 0 longitude 0 accommodation_type 0 cost 0 minimum_nights 0 number_of_reviews 0 reviews_per_month 676 owner_id 0 owned_hotels 0 yearly_availability 0 dtype: int64 '''
Заполнение пустых значений в столбце Reviews_per_month с помощью 0. Это связано с тем, что этот столбец может быть очень ценным как функция, и эти строки с нулевыми значениями нельзя игнорировать, поскольку все остальные столбцы имеют некоторое значение. количество отзывов в месяц может указывать на то, что это будет зависеть от того, сколько людей посетило это место. т. е. чем больше людей посетило отель, тем больше шансов, что они напишут отзыв, и, следовательно, это также означает, что отель может быть менее доступен из года в год из-за спроса.
data.reviews_per_month = data.reviews_per_month.fillna(0)
# Converting the categorical column values to independent columns with values 0 and 1 data = pd.get_dummies(data, drop_first =True) data
# removing non-relevant fields - these may not be usefull for model training
train_data = data.drop(['id','latitude','longitude','owner_id'], axis = 1)
Визуализация, моделирование, машинное обучение
#Loading Test data
test_data=pd.read_csv('test.csv')
test_data.head()
Преобразование и очистка тестовых данных
test_data.isnull().sum(axis=0)
''' id 0 region 0 latitude 0 longitude 0 accommodation_type 0 cost 0 minimum_nights 0 number_of_reviews 0 reviews_per_month 173 owner_id 0 owned_hotels 0 dtype: int64 '''
test_data.reviews_per_month = test_data.reviews_per_month.fillna(0)
test_data = pd.get_dummies(test_data, drop_first =True)
test_data_feature = test_data.drop(['id','latitude','longitude','owner_id'], axis = 1)
test_data_feature
Проверка корреляции между функциями
import seaborn as sns
import matplotlib.pyplot as plt
corr_df = train_data.corr()
corr_df
ax = plt.axes()
sns.heatmap(corr_df, ax = ax)
ax.set_title('Correlation between features')
plt.show()
corr_df_viz = corr_df corr_df_viz['feature'] = corr_df_viz.index plt.figure(figsize=(10,6)) # make barplot sns.barplot(x='feature', y="yearly_availability", data=corr_df_viz, order=corr_df_viz.sort_values('yearly_availability', ascending = False).feature) # set labels plt.xlabel("Feature", size=15) plt.ylabel("Correlation between Yearly Availability", size=15) plt.title("Top 20 Features", size=18) plt.tight_layout() plt.xticks(rotation=80)
#(array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), # <a list of 12 Text xticklabel objects>)
Приведенный выше график показывает нам, что тип жилья, минимальное количество ночей пребывания человека, стоимость и регион имеют положительную корреляцию, в то время как такие характеристики, как число_отзывов, количество отзывов_за_месяц, имеют отрицательную корреляцию, т. е. если эти числа больше, годовая доступность с меньшей вероятностью равна 1.
Создание модели
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline from sklearn.metrics import accuracy_score, confusion_matrix ,classification_report import numpy as np
# Checking distribution of yearly_availability column in the training data f, ax = plt.subplots(figsize=(7, 5)) sns.countplot(x='yearly_availability', data=train_data) plt.title('# Availability vs Non Availability') plt.xlabel('Class (1==Availability)')
#Text(0.5, 0, 'Class (1==Availability)')
Поскольку у нас есть сопоставимое количество записей для обоих классов, мы можем использовать показатели точности для производительности.
# Splitting data to train and test np.random.seed(42) X = train_data.drop(['yearly_availability' ], axis = 1) y = train_data['yearly_availability'] X_train, X_test, y_train, y_test = train_test_split(X, y)
# Using Logistic regression for Binary Classification scaler = StandardScaler() lr = LogisticRegression(solver = 'lbfgs') model1 = Pipeline([('standardize', scaler), ('log_reg', lr)])
model1.fit(X_train, y_train)
Pipeline(memory=None, steps=[('standardize', StandardScaler(copy=True, with_mean=True, with_std=True)), ('log_reg', LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, l1_ratio=None, max_iter=100, multi_class='warn', n_jobs=None, penalty='l2', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False))], verbose=False)
# Accuracy for Train Split y_train_h = model1.predict(X_train) y_train_h_probs = model1.predict_proba(X_train)[:,1] train_accuracy = accuracy_score(y_train, y_train_h)*100 print('Confusion matrix:\n', confusion_matrix(y_train, y_train_h)) print('Training accuracy: %.4f %%' % train_accuracy)
''' Confusion matrix: [[945 137] [169 901]] Training accuracy: 85.7807 % '''
# Accuracy for Test Split y_test_h = model1.predict(X_test) y_test_h_probs = model1.predict_proba(X_test)[:,1] test_accuracy = accuracy_score(y_test, y_test_h)*100 print('Confusion matrix:\n', confusion_matrix(y_test, y_test_h)) print('Testing accuracy: %.4f %%' % test_accuracy)
''' Confusion matrix: [[313 44] [ 56 305]] Testing accuracy: 86.0724 % '''
print(classification_report(y_test, y_test_h, digits=5))
''' precision recall f1-score support 0 0.84824 0.87675 0.86226 357 1 0.87393 0.84488 0.85915 361 accuracy 0.86072 718 macro avg 0.86108 0.86081 0.86071 718 weighted avg 0.86115 0.86072 0.86070 718 '''
# Combining prediction results to IDs. pred_list = list(model1.predict(test_data_feature)) pred_id = list(test_data['id']) submission_df = pd.DataFrame(list(zip(pred_list,pred_id )), columns = ['id','yearly_availability'])
submission_df
submission_df.to_csv('submissions.csv',index=False)
Результаты. Мы смогли достичь точности 86 % в модели логистической регрессии и предсказать значения тестовых данных с помощью этой модели. Дальнейшие улучшения можно внести, проанализировав, какие функции можно игнорировать при обучении модели.