Skip to content

Python для анализа и визуализации данных

Пересказ статьи Muhammad Sa'duddin. Python for Data Analysis and Data Visualization


Ранее мы обсуждали анализ данных с помощью SQL. Теперь я выполню анализ данных, используя Python. Но прежде, если вы хотите прочитать мою статью об анализе с помощью SQL, вот ссылка.

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

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

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import re
sns.set()

Затем импортируем набор данных, используемый для анализа:

df_hotels = pd.read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-02-11/hotels.csv')

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

df_hotels = df_hotels.reset_index().rename(columns={'index':'id'})

Теперь давайте начнем анализ данных с использованием Python.

Вопрос 1
Какой тип данных используется в наборе данных? Каково число и процентное отношение NULL-значений, а также число уникальных значений в наборе данных?

Решение 1
Мы можем проверить тип данных, число и процентное отношение NULL-значений, число уникальных значений, используя следующий синтаксис:

def check_values(df):
data = []
for col in df.columns:
data.append([col, \
df[col].dtype, \
df[col].isna().sum(), \
round(100*(df[col].isna().sum()/len(df)),2), \
df[col].nunique()
])
return pd.DataFrame(columns=['dataFeatures', 'dataType', 'null', 'nullPct', 'unique'],data=data)

check_values(df_hotels)



Вопрос 2
Сколько посетителей отменили бронь, а сколько нет? И по этому количеству сделать вывод о доле каждого!

Ответ 2
Вот синтаксис для нахождения посетителей, кто отменил бронь. 0 означает, что посетитель не отменял бронь, а 1 означает отмену брони посетителем.

df_hotels.is_canceled.value_counts()



Видно, что 44224 посетителей отменили бронь. Соотношение тех, кто отменил бронь и кто не отменял, представлено ниже.

sns.countplot(data=df_hotels, x='is_canceled')
plt.title('Cancelled')
plt.show()



Процентное отношение тех, кто отменял бронь и кто не отменял:

df_hotels.is_canceled.value_counts(normalize=True)*100



Как видно, 37,04% посетителей отменило бронь.

Вопрос 3
A. Каково процентное отношение отмененной брони для "City Hotel"?
B. Каково процентное отношение отмененной брони для "Resort Hotels"?

Решение 3
Процентное отношение посетителей, кто отменил бронь в "City Hotel", составляет 41,72%, а для "Resort Hotels" этот процент составляет 27,76%, что можно увидеть в результатах ниже.

# Синтаксис для А
df_hotels[df_hotels.hotel=='City Hotel'].is_canceled.value_counts(normalize=True)
print("Percentage =",len(df_hotels[(df_hotels.hotel=='City Hotel')&(df_hotels.is_canceled==1)]) 100 / len(df_hotels[(df_hotels.hotel=='City Hotel')]),"%")



# Синтаксис для В
df_hotels[df_hotels.hotel=='Resort Hotel'].is_canceled.value_counts(normalize=True)
print("Percentage =",len(df_hotels[(df_hotels.hotel=='Resort Hotel')&(df_hotels.is_canceled==1)])
100 / len(df_hotels[(df_hotels.hotel=='Resort Hotel')]),"%")



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

Решение 4
Ниже приведен синтаксис и результаты фильтрации для отображения только тех посетителей, которые не отменяли бронь.

df_hotels[df_hotels.is_canceled==0]



Затем сохраним результат в переменной df_checkout, используя следующий синтаксис:

df_checkout = df_hotels[df_hotels.is_canceled==0]

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

Решение 5
Число бронирований по месяцам для каждого типа отелей показано ниже.

summary_tiap_hotel = df_checkout.groupby(['hotel','arrival_date_month']).size().reset_index()
summary_tiap_hotel.columns = ['hotel','arrival_date_month','jumlah_reservasi']
summary_tiap_hotel



Наибольшее число бронирований для City Hotel и Resort Hotel наблюдается в августе. Эти данные можно увидеть ниже.

max_ch = summary_tiap_hotel[summary_tiap_hotel['hotel'] == 'City Hotel']['jumlah_reservasi'].max()
max_rh = summary_tiap_hotel[summary_tiap_hotel['hotel'] == 'Resort Hotel']['jumlah_reservasi'].max()

print('summary max reservasi City Hotel')
display(summary_tiap_hotel[summary_tiap_hotel['jumlah_reservasi'] == max_ch])

print('')
print('')

print('summary max reservasi Resort Hotel')
display(summary_tiap_hotel[summary_tiap_hotel['jumlah_reservasi'] == max_rh])



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

import calendar
month_dict = {month: index for index, month in enumerate(calendar.month_name) if month}
df_checkout['arrival_date_month_num'] = df_checkout['arrival_date_month'].map(month_dict)
df_checkout.groupby(['hotel','arrival_date_month_num']).size()

rf_df = df_checkout[df_checkout['hotel'] == "Resort Hotel"]
cf_df = df_checkout[df_checkout['hotel'] == "City Hotel"]

Теперь давайте посмотрим тренд.

sns.lineplot(data = rf_df, x = 'arrival_date_month_num', y = 'id').set_title('Trend Resort Hotel Monthly')



sns.lineplot(data = cf_df, x = 'arrival_date_month_num', y = 'id').set_title('Trend City Hotel Monthly')



sns.countplot(data=df_checkout, x='arrival_date_month_num',hue='hotel')
plt.xlabel('bulan kedatangan')
plt.ylabel('jumlah reservasi')
plt.show()



Вопрос 6
А. Создать новый столбец с именем arrival_date, который содержит полную информацию о годе, месяце и дате прибытия.
В. Изменить тип столбца на DateTime.

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

df_checkout['arrival_date'] = \
df_checkout['arrival_date_year'].astype('str') + '-' +\
df_checkout.arrival_date_month_num.astype('str').str.pad(2,fillchar='0') + '-' +\
df_checkout.arrival_date_day_of_month.astype('str').str.pad(2,fillchar='0')

Тип данных столбца arrival_date:

df_checkout.arrival_date.dtype



Теперь изменим тип данных столбца. Мы изменим тип данных столбца arrival_date на DateTime и проверим изменение с помощью следующего кода:

df_checkout['arrival_date'] = pd.to_datetime(df_checkout.arrival_date)
df_checkout['arrival_date']



Вопрос 7
Создать 2 фрейма данных, выводящих следующее:
1. Общее бронирование за день.
2. Среднее ежедневное бронирование за каждую неделю.

Решение 7
Фрейм данных общего ежедневного бронирования и его тренд представлены ниже.

df_reservation_perday = df_checkout.resample('D',on='arrival_date').size().reset_index().rename(columns={0:'total_reservation'})
df_reservation_perday



plt.figure(figsize=(10,4))
sns.lineplot(data=df_reservation_perday, x='arrival_date', y='total_reservation')
plt.title('Reservation per Day', fontsize='x-large')
plt.show()



Фрейм данных для среднего ежедневного бронирования за каждую неделю и его тренд представлены ниже.

df_avg_reservation_perday = df_checkout.resample('D',on='arrival_date').size().reset_index().rename(columns={0:'total_reservation'}).\
resample('W',on='arrival_date')['total_reservation'].mean().reset_index()
df_avg_reservation_perday



plt.figure(figsize=(10,4))
sns.lineplot(data=df_avg_reservation_perday, x='arrival_date', y='total_reservation')
plt.title('Average Reservation per Day', fontsize='x-large')
plt.show()



Вопрос 8
А. Каково среднее значение ADR (средняя цена номероночи) по типу отеля и типу заказчика (customer_type)?
В. Какой тип заказчика имеет наибольший ADR для каждого типа отеля?

Решение 8
Среднее значение ADR по типу отеля и типу заказчика можно увидеть ниже.

customer_summary = df_checkout.groupby(['hotel','customer_type'])['adr'].mean().reset_index()
customer_summary



Наибольший ADR для каждого типа отеля имеет заказчик типа Transient. Это можно увидеть на результатах ниже.

max_chs = customer_summary[customer_summary['hotel'] == 'City Hotel']['adr'].max()
max_rhs = customer_summary[customer_summary['hotel'] == 'Resort Hotel']['adr'].max()
display(customer_summary[customer_summary['adr'] == max_chs])
print('')
print('')
display(customer_summary[customer_summary['adr'] == max_rhs])



Вопрос 9
Вывести 10 стран с наибольшим числом бронирований!

Решение 9
Шаг 1
Импортируем df_country и чистим данные.

df_country = pd.read_csv('https://gist.githubusercontent.com/tadast/8827699/raw/f5cac3d42d16b78348610fc4ec301e9234f82821/countries_codes_and_coordinates.csv')
df_country['code'] = df_country['Alpha-3 code'].str.replace('"','').str.strip()

Шаг 2
Выполняем слияние фреймов данных df_checkout и df_country. Используем поле 3-символьного кода, чтобы получить название страны.

df_merged = pd.merge(df_checkout[['id','country']],
df_country[['Country','code']],
left_on='country',
right_on='code',
indicator=True,
how='left')

Шаг 3
Выводим 10 стран с наибольшим числом бронирования.

df_merged.Country.value_counts().head(10)



Шаг 4
Визуализация

df_merged.Country.value_counts().head(10).sort_values(ascending=True).plot.barh()
plt.show()



Вопрос 10
А. Сколько гостей проживает по каждому бронированию?
В. На основе этого набора данных определить максимальное число гостей. Вывести также строку данных бронирования с максимальным числом гостей.

Решение 10
Число гостей на каждое бронирование составляет 1,94 (округлено до 2).
Максимальное число гостей равно 12. Эти данные можно увидеть в строках mean и max в результатах ниже.

df_checkout['total_guest'] = df_checkout.adults + df_checkout.children + df_checkout.babies
df_checkout.total_guest.describe()



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

df_checkout[df_checkout.total_guest==df_checkout.total_guest.max()].T




Ссылки по теме
1. Команды Pandas, которые я часто использую для анализа данных
2. Получение в Python данных из MySQL

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.