Ciencia y Tecnología

Análisis Exploratorio de Datos – Demanda de Reservas Hoteleras

Para este proyecto de Análisis Exploratorio de Datos (EDA), vamos a utilizar el conjunto de datos «Demanda de reservas de hotel», que puede encontrarse aquí

Este conjunto de datos contiene información sobre las reservas de un hotel urbano y un hotel turístico, e incluye datos como la fecha de la reserva, la duración de la estancia, el número de adultos, niños y/o bebés, y el número de plazas de aparcamiento disponibles, entre otros.

Se ha eliminado de los datos toda la información de identificación personal.

Los datos proceden originalmente del artículo Hotel Booking Demand Datasets, escrito por Nuno Antonio, Ana Almeida y Luis Nunes para Data in Brief, Volumen 22, febrero de 2019.

Los datos fueron descargados y limpiados por Thomas Mock y Antoine Bichat para #TidyTuesday durante la semana del 11 de febrero de 2020.

Preparación y limpieza de datos

El primer paso es importar las principales librerías que utilizaremos para este proyecto.

In [ ]:

import pandas as pd
import seaborn as sns
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
from sklearn.preprocessing import StandardScaler
pd.set_option('display.max_columns', 500)

Ahora, descargamos el conjunto de datos para utilizarlo como un pandas dataframe.

In [ ]:

url = 'https://raw.githubusercontent.com/salves94/hotel-exploratory-data-analysis/master/hotel_bookings.csv'
df = pd.read_csv(url)

Comprobamos cuántas filas tiene el conjunto de datos

In [ ]:

len(df.index)

Out[ ]:

119390

Ahora sabemos que nuestro conjunto de datos tiene 119390 filas.

Ahora vamos a comprobar cuántas celdas faltan en nuestro conjunto de datos.

In [ ]:

df.isnull().sum()

Out[ ]:

hotel                                  0
is_canceled                            0
lead_time                              0
arrival_date_year                      0
arrival_date_month                     0
arrival_date_week_number               0
arrival_date_day_of_month              0
stays_in_weekend_nights                0
stays_in_week_nights                   0
adults                                 0
children                               4
babies                                 0
meal                                   0
country                              488
market_segment                         0
distribution_channel                   0
is_repeated_guest                      0
previous_cancellations                 0
previous_bookings_not_canceled         0
reserved_room_type                     0
assigned_room_type                     0
booking_changes                        0
deposit_type                           0
agent                              16340
company                           112593
days_in_waiting_list                   0
customer_type                          0
adr                                    0
required_car_parking_spaces            0
total_of_special_requests              0
reservation_status                     0
reservation_status_date                0
dtype: int64

Podemos ver que tenemos 4 columnas con valores perdidos. Vamos a comprobar estos valores como porcentajes.

In [ ]:

df.isnull().sum()/len(df.index)*100

Out[ ]:

hotel                              0.000000
is_canceled                        0.000000
lead_time                          0.000000
arrival_date_year                  0.000000
arrival_date_month                 0.000000
arrival_date_week_number           0.000000
arrival_date_day_of_month          0.000000
stays_in_weekend_nights            0.000000
stays_in_week_nights               0.000000
adults                             0.000000
children                           0.003350
babies                             0.000000
meal                               0.000000
country                            0.408744
market_segment                     0.000000
distribution_channel               0.000000
is_repeated_guest                  0.000000
previous_cancellations             0.000000
previous_bookings_not_canceled     0.000000
reserved_room_type                 0.000000
assigned_room_type                 0.000000
booking_changes                    0.000000
deposit_type                       0.000000
agent                             13.686238
company                           94.306893
days_in_waiting_list               0.000000
customer_type                      0.000000
adr                                0.000000
required_car_parking_spaces        0.000000
total_of_special_requests          0.000000
reservation_status                 0.000000
reservation_status_date            0.000000
dtype: float64

Las columnas «agente» y «empresa» tienen un alto porcentaje de valores perdidos. Como estas columnas no serán relevantes para nuestro análisis, podemos eliminarlas.

In [ ]:

df=df.drop(['agent','company'],axis=1) # Eliminamos las columnas de agente y empresa

Las columnas «niños» y «país» tienen un bajo porcentaje de valores omitidos. Eliminaremos la fila completa en las celdas que faltan.

In [ ]:

df = df.dropna(axis = 0) # Eliminamos las filas con celdas vacías

Ahora eliminaremos la columna days_in_waiting_list porque no la utilizaremos para este análisis

In [ ]:

df = df.drop(labels='days_in_waiting_list', axis=1) # Eliminamos la columna days_in_waiting_list

Comprobemos de nuevo los valores que faltan.

In [ ]:

df.isnull().sum()

Out[ ]:

hotel                             0
is_canceled                       0
lead_time                         0
arrival_date_year                 0
arrival_date_month                0
arrival_date_week_number          0
arrival_date_day_of_month         0
stays_in_weekend_nights           0
stays_in_week_nights              0
adults                            0
children                          0
babies                            0
meal                              0
country                           0
market_segment                    0
distribution_channel              0
is_repeated_guest                 0
previous_cancellations            0
previous_bookings_not_canceled    0
reserved_room_type                0
assigned_room_type                0
booking_changes                   0
deposit_type                      0
customer_type                     0
adr                               0
required_car_parking_spaces       0
total_of_special_requests         0
reservation_status                0
reservation_status_date           0
dtype: int64

Perfecto, ahora no nos falta ningún valor.

Vamos a echar un vistazo más de cerca a lo que tenemos.

In [ ]:

df.describe()

Out[ ]:

is_canceledlead_timearrival_date_yeararrival_date_week_numberarrival_date_day_of_monthstays_in_weekend_nightsstays_in_week_nightsadultschildrenbabiesis_repeated_guestprevious_cancellationsprevious_bookings_not_canceledbooking_changesadrrequired_car_parking_spacestotal_of_special_requests
count118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000118898.000000
mean0.371352104.3114352016.15765627.16655515.8008800.9288972.5021451.8583910.1042070.0079480.0320110.0871420.1316340.221181102.0032430.0618850.571683
std0.483168106.9033090.70745913.5899718.7803240.9962161.9001680.5785760.3991720.0973800.1760290.8458691.4846720.65278550.4858620.2441720.792678
min0.0000000.0000002015.0000001.0000001.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000-6.3800000.0000000.000000
25%0.00000018.0000002016.00000016.0000008.0000000.0000001.0000002.0000000.0000000.0000000.0000000.0000000.0000000.00000070.0000000.0000000.000000
50%0.00000069.0000002016.00000028.00000016.0000001.0000002.0000002.0000000.0000000.0000000.0000000.0000000.0000000.00000095.0000000.0000000.000000
75%1.000000161.0000002017.00000038.00000023.0000002.0000003.0000002.0000000.0000000.0000000.0000000.0000000.0000000.000000126.0000000.0000001.000000
max1.000000737.0000002017.00000053.00000031.00000016.00000041.00000055.00000010.00000010.0000001.00000026.00000072.00000021.0000005400.0000008.0000005.000000

Aquí podemos ver algunos valores atípicos.

Vamos a construir gráficos de caja para verlo mejor.

In [ ]:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

columns = ['lead_time', 'stays_in_weekend_nights', 'stays_in_week_nights', 'adults', 'children', 'babies', 'required_car_parking_spaces', 'adr', 'previous_cancellations', 'previous_bookings_not_canceled', 'booking_changes']
n = 1
plt.figure(figsize=(20,15))

for column in columns:
  plt.subplot(4,4,n)
  n = n+1
  sns.boxplot( df[ column ] )
  plt.tight_layout()

Eliminamos los valores atípicos utilizando condicionales para obtener y actualizar estos valores.

In [ ]:

df.loc[df.lead_time > 500, 'lead_time'] = 500
df.loc[df.stays_in_weekend_nights >=  5, 'stays_in_weekend_nights'] = 5
df.loc[df.adults > 4, 'adults'] = 4
df.loc[df.previous_bookings_not_canceled > 0, 'previous_bookings_not_canceled'] = 1
df.loc[df.previous_cancellations > 0, 'previous_cancellations'] = 1
df.loc[df.stays_in_week_nights > 10, 'stays_in_week_nights'] = 10
df.loc[df.booking_changes > 5, 'booking_changes'] = 5
df.loc[df.babies > 8, 'babies'] = 0
df.loc[df.required_car_parking_spaces > 5, 'required_car_parking_spaces'] = 0
df.loc[df.children > 8, 'children'] = 0
df.loc[df.adr > 1000, 'adr'] = 1000

Hemos eliminado los valores atípicos. Ahora nuestros datos están limpios.

Análisis exploratorio y visualización

En esta sección exploraremos los datos para obtener información sobre ellos.

Vamos a combinar las columnas «niños» y «bebés» en la columna «niños».

A continuación, establecemos el tipo de cadena en las columnas correspondientes.

In [ ]:

df['kids'] = df.children + df.babies

#Combine total mumbers by adding kids and adults
df['total_members'] = df.kids + df.adults
#convert the datatypes to string
df['arrival_date_year'] = df['arrival_date_year'].astype('str')
df['arrival_date_month'] = df['arrival_date_month'].astype('str')
df['arrival_date_day_of_month'] = df['arrival_date_day_of_month'].astype('str')
df['is_canceled'] = df['is_canceled'].astype('str')
df['is_repeated_guest'] = df['is_repeated_guest'].astype('str')

Convirtamos la fecha de llegada en fecha-hora

In [ ]:

df['arrival_date'] = df['arrival_date_day_of_month'] + '-' + df['arrival_date_month'] + '-' + df['arrival_date_year']
df['arrival_date'] = pd.to_datetime(df['arrival_date'], errors='coerce')

A) Reservas confirmadas

Veamos cuántas reservas confirmadas hay al mes.

In [ ]:

import datetime as dt

confirmed_bookings = df[df.is_canceled=='0']

confirmed_bookings['arrival_date_month'] = df['arrival_date'].dt.month
final=confirmed_bookings['arrival_date_month'].value_counts().sort_index()
final
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:5: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  """

Out[ ]:

1     4068
2     5317
3     6591
4     6533
5     7102
6     6393
7     7892
8     8618
9     6367
10    6867
11    4632
12    4365
Name: arrival_date_month, dtype: int64

Las reservas confirmadas pasan de su valor más bajo (4068) en enero a su valor más alto (8618) en agosto.

B) Reservas canceladas

Ahora vamos a comprobar las reservas canceladas.

In [ ]:

print('Total Bookings cancelled')
print(df.is_canceled.value_counts())
print('Cancelation percentage')
print(df.is_canceled.value_counts(normalize=True))
Total Bookings cancelled
0    74745
1    44153
Name: is_canceled, dtype: int64
Cancelation percentage
0    0.628648
1    0.371352
Name: is_canceled, dtype: float64

Durante el año, tenemos un 37,13% de cancelaciones.

Ahora vamos a trazar este resultado.

In [ ]:

plt.figure(figsize=(8,8))

#Canceled=1, Not canceled= 0
sns.countplot(df['is_canceled'], palette='husl')
plt.show()

C) País

Aquí comprobaremos el país de origen. Las categorías se representan en el formato ISO 3155-3:2013.

In [ ]:

df.country.value_counts(normalize=True)

Out[ ]:

PRT    0.408636
GBR    0.102012
FRA    0.087596
ESP    0.072062
DEU    0.061288
         ...   
NCL    0.000008
MMR    0.000008
CYM    0.000008
MRT    0.000008
SDN    0.000008
Name: country, Length: 177, dtype: float64

D) Mes

Ahora vamos a comprobar la fecha de llegada por meses.

In [ ]:

df.arrival_date_month.value_counts(normalize=True)

Out[ ]:

August       0.116503
July         0.106209
May          0.099068
October      0.093315
April        0.092895
June         0.091902
September    0.088033
March        0.081911
February     0.067385
November     0.056788
December     0.056586
January      0.049404
Name: arrival_date_month, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['arrival_date_month'], palette='husl')
plt.show()

E) Segmento de mercado

Comprobemos la designación del segmento de mercado. En las categorías, el término «AT» significa «agencias de viajes» y «TO» significa «turoperadores».

In [ ]:

df.market_segment.value_counts(normalize=True)

Out[ ]:

Online TA        0.474373
Offline TA/TO    0.203199
Groups           0.166580
Direct           0.104695
Corporate        0.042986
Complementary    0.006173
Aviation         0.001993
Name: market_segment, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['market_segment'], palette='husl')
plt.show()

F) Año

Año de la fecha de llegada.

In [ ]:

df.arrival_date_year.value_counts(normalize=True)

Out[ ]:

2016    0.474651
2017    0.341503
2015    0.183847
Name: arrival_date_year, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['arrival_date_year'], palette='husl')
plt.show()

G) Comida

Tipo de comida reservada. Las categorías se presentan en paquetes de comidas de hospitalidad estándar:

  • Undefined/SC – sin paquete de comidas.
  • BB – Bed & Breakfast.
  • HB – Half board (desayuno y otra comida, normalmente la cena).
  • FB – Full board (desayuno, comida y cena).

In [ ]:

df.meal.value_counts(normalize=True)

Out[ ]:

BB           0.772620
HB           0.121398
SC           0.089472
Undefined    0.009798
FB           0.006712
Name: meal, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['meal'], palette='husl')
plt.show()

H) Customer Type

Tipo de reserva, asumiendo una de las cuatro categorías:

  • Contract – cuando la reserva tiene asociada una adjudicación u otro tipo de contrato.
  • Group – cuando la reserva está asociada a un grupo.
  • Transient – cuando la reserva no forma parte de un grupo o contrato, y no está asociada a otra reserva transitoria.
  • Transient-party – cuando la reserva es transitoria, pero está asociada al menos a otra reserva transitoria.

In [ ]:

df.customer_type.value_counts(normalize=True)

Out[ ]:

Transient          0.750004
Transient-Party    0.210920
Contract           0.034281
Group              0.004794
Name: customer_type, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['customer_type'], palette='husl')
plt.show()

I) Tipo de habitación reservada

Código del tipo de habitación reservada. El código se presenta en lugar de la designación por razones de anonimato.

In [ ]:

df.reserved_room_type.value_counts(normalize=True)

Out[ ]:

A    0.719953
D    0.161256
E    0.054643
F    0.024307
G    0.017519
B    0.009369
C    0.007830
H    0.005055
L    0.000050
P    0.000017
Name: reserved_room_type, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['reserved_room_type'], palette='husl')
plt.show()

J) Tipo de habitación asignada

Código del tipo de habitación asignado a la reserva. A veces, el tipo de habitación asignado difiere del tipo de habitación reservado por motivos de funcionamiento del hotel (por ejemplo, exceso de reservas) o a petición del cliente. El código se presenta en lugar de la designación por razones de anonimato.

In [ ]:

df.assigned_room_type.value_counts(normalize=True)

Out[ ]:

A    0.621230
D    0.211660
E    0.065081
F    0.031388
G    0.021354
C    0.019798
B    0.018158
H    0.005955
I    0.003003
K    0.002347
P    0.000017
L    0.000008
Name: assigned_room_type, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['assigned_room_type'], palette='husl')
plt.show()

K) Cambios en las reservas

Número de cambios/enmiendas realizados en la reserva desde el momento en que se introdujo la reserva en el PMS hasta el momento de la facturación o cancelación.

In [ ]:

df.booking_changes.value_counts(normalize=True)

Out[ ]:

0    0.848643
1    0.106301
2    0.031876
3    0.007780
4    0.003154
5    0.002246
Name: booking_changes, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['booking_changes'], palette='husl')
plt.show()

l) Canal de distribución

Canal de distribución de reservas. El término «AT» significa «agencias de viajes» y «TO» significa «turoperadores».

In [ ]:

df.distribution_channel.value_counts(normalize=True)

Out[ ]:

TA/TO        0.821965
Direct       0.121810
Corporate    0.054593
GDS          0.001623
Undefined    0.000008
Name: distribution_channel, dtype: float64

In [ ]:

plt.figure(figsize=(14,7))
sns.countplot(df['distribution_channel'], palette='husl')
plt.show()

M) Invitado repetido

Compruebe si el nombre de la reserva procede de un huésped repetido.

In [ ]:

df.is_repeated_guest.value_counts(normalize=True)

Out[ ]:

0    0.967989
1    0.032011
Name: is_repeated_guest, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['is_repeated_guest'], palette='husl')
plt.show()

N) Tipo de depósito

Indicación de si el cliente hizo un depósito para garantizar la reserva. Esta variable puede asumir tres categorías:

  • No Deposit – no se ha realizado ningún depósito.
  • Non Refund – se ha realizado un depósito por valor del coste total de la estancia.
  • Refundable – se ha realizado un depósito con un valor inferior al coste total de la estancia.

In [ ]:

df.deposit_type.value_counts(normalize=True)

Out[ ]:

No Deposit    0.876070
Non Refund    0.122567
Refundable    0.001363
Name: deposit_type, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['deposit_type'], palette='husl')
plt.show()

O) Plazas de aparcamiento obligatorias

Número de plazas de aparcamiento que necesita el cliente.

In [ ]:

df.required_car_parking_spaces.value_counts(normalize=True)

Out[ ]:

0    0.938536
1    0.061204
2    0.000235
3    0.000025
Name: required_car_parking_spaces, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['required_car_parking_spaces'], palette='husl')
plt.show()

P) Total de miembros

Total de miembros por reserva.

In [ ]:

df.total_members.value_counts(normalize=True)

Out[ ]:

2.0    0.688674
1.0    0.187472
3.0    0.088134
4.0    0.033154
0.0    0.001430
5.0    0.001135
Name: total_members, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['total_members'], palette='husl')
plt.show()

Q) Estado de la reserva

Estado de última reserva, asumiendo una de las tres categorías:

  • Canceled – El cliente ha cancelado la reserva.
  • Check-Out – el cliente se ha registrado pero ya se ha marchado.
  • No-Show – El cliente no se registró e informó al hotel del motivo.

In [ ]:

df.reservation_status.value_counts(normalize=True)

Out[ ]:

Check-Out    0.628648
Canceled     0.361234
No-Show      0.010118
Name: reservation_status, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['reservation_status'], palette='husl')
plt.show()

R) Tipo de hotel

Veamos la proporción de reservas entre tipos de hotel.

In [ ]:

df.hotel.value_counts(normalize=True)

Out[ ]:

City Hotel      0.666975
Resort Hotel    0.333025
Name: hotel, dtype: float64

In [ ]:

plt.figure(figsize=(6,6))
sns.countplot(df['hotel'], palette='husl')
plt.show()

S) Relación entre los precios y el mes

In [ ]:

plt.figure(figsize=(12,5))

# Calculating average daily rate per person
df['adr_pp'] = df['adr'] / (df['adults'] + df['children']) 
actual_guests = df.loc[df["is_canceled"] == '0']
actual_guests['price'] = actual_guests['adr'] * (actual_guests['stays_in_weekend_nights'] + actual_guests['stays_in_week_nights'])
sns.lineplot(data = actual_guests, x = 'arrival_date_month', y = 'price', hue = 'hotel')
plt.show()
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:6: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Aquí podemos ver que los precios de los hoteles vacacionales son más altos y fluctúan más que los de los hoteles urbanos.

T) ADR

In [ ]:

plt.figure(figsize=(12,6))
sns.lineplot(x='arrival_date_month', y='adr', hue='hotel', data= df)
plt.show()

En los hoteles turísticos, la tarifa media diaria es más cara en agosto, julio y septiembre.

En los hoteles urbanos, la tarifa media diaria es más cara en agosto, julio, junio y mayo.

Formulación de Preguntas

Ahora formularemos y responderemos algunas preguntas interesantes sobre los datos.

¿Cuáles son los tres países de origen más comunes y los menos comunes?

In [ ]:

print('Most common countries:')
print(df.country.value_counts().head(3))
print('-'*50)
print('\n Most uncommon countries:')
print(df.country.value_counts().tail(35))
Most common countries:
PRT    48586
GBR    12129
FRA    10415
Name: country, dtype: int64
--------------------------------------------------

 Most uncommon countries:
MWI    2
COM    2
SYC    2
MYT    2
TGO    2
MDG    1
DMA    1
MLI    1
GUY    1
PLW    1
KIR    1
PYF    1
LCA    1
BHS    1
FJI    1
NAM    1
UMI    1
NIC    1
DJI    1
NPL    1
BDI    1
BWA    1
VGB    1
SLE    1
BFA    1
SMR    1
AIA    1
ATF    1
ASM    1
HND    1
NCL    1
MMR    1
CYM    1
MRT    1
SDN    1
Name: country, dtype: int64

Como vemos, Portugal encabeza la lista con 48.586 de los casos, seguido de Gran Bretaña con 12.129 y Francia con 10.415.

Hay 30 países que pueden considerarse como el país de origen más infrecuente, con 1 huésped por país. Entre ellos figuran Madagascar, Dominica, Malí, Guyana, Palaos, Kiribati, Sudán, etc.

¿Cuáles son los meses de mayor y menor ocupación?

In [ ]:

df.arrival_date_month.value_counts(normalize=True)

Out[ ]:

August       0.116503
July         0.106209
May          0.099068
October      0.093315
April        0.092895
June         0.091902
September    0.088033
March        0.081911
February     0.067385
November     0.056788
December     0.056586
January      0.049404
Name: arrival_date_month, dtype: float64

El mes de mayor ocupación es agosto con el 11,65% de las reservas. El mes de menor ocupación es enero con el 4,94% de las reservas.

¿Cuál es el paquete de comidas más popular?

In [ ]:

df.meal.value_counts(normalize=True)

Out[ ]:

BB           0.772620
HB           0.121398
SC           0.089472
Undefined    0.009798
FB           0.006712
Name: meal, dtype: float64

La opción Bed & Breakfast es la más popular, con una frecuencia del 77,26%.

¿Cuál es el tipo de habitación más reservado?

In [ ]:

df.reserved_room_type.value_counts(normalize=True)

Out[ ]:

A    0.719953
D    0.161256
E    0.054643
F    0.024307
G    0.017519
B    0.009369
C    0.007830
H    0.005055
L    0.000050
P    0.000017
Name: reserved_room_type, dtype: float64

El tipo de habitación «A» es el más popular entre los clientes, con el 71,99% de las reservas.

¿Cuántos cambios de reservas se han realizado durante el periodo estudiado?

In [ ]:

df.booking_changes.sum()

Out[ ]:

25829

Durante este periodo se registraron 25.829 cambios en las reservas.

¿Cuántas personas se han registrado en el hotel?

In [ ]:

df.total_members.sum()

Out[ ]:

233934.0

233.934 personas se han registrado en el hotel.

¿Cuántas plazas de aparcamiento se han utilizado?

In [ ]:

df.required_car_parking_spaces.sum()

Out[ ]:

7342

Se han utilizado 7.342 plazas de aparcamiento.

¿Cuál es el tipo de cliente más habitual?

In [ ]:

df.customer_type.value_counts(normalize=True)

Out[ ]:

Transient          0.750004
Transient-Party    0.210920
Contract           0.034281
Group              0.004794
Name: customer_type, dtype: float64

Los clientes de tipo Transient son los más comunes, representando el 75% del total de clientes.

Inferencias y conclusión

  • La mayoría de los huéspedes proceden de países de Europa Occidental.
  • La mayoría de las reservas son para hoteles urbanos.
  • El número de huéspedes que repiten es muy bajo.
  • La mayoría de las reservas se convierten en transacciones con éxito.

Referencias

Sergio Alves

Ingeniero de Sistemas. MSc. en Data Science. Cuento con una amplia trayectoria profesional en las áreas de Desarrollo Web FullStack, DBA, DevOps, Inteligencia Artificial y Ciencia de Datos. Soy un entusiasta de la música, la tecnología y el aprendizaje contínuo.

Artículos Relacionados

Back to top button