Exploración y aprendizaje automático para los listados de Airbnb en Toronto

Crédito de la foto: Dentro de Airbnb

Airbnb no proporciona datos abiertos en el sentido de bases de datos gigantes o volcados con los que podemos trabajar. Sin embargo, Inside Airbnb utiliza información pública recopilada del sitio web de Airbnb y analiza la información disponible al público sobre las listas de Airbnb de una ciudad, y proporciona filtros y métricas clave para que podamos ver cómo se está utilizando Airbnb en las principales ciudades. alrededor del mundo. Inside Airbnb es un conjunto de herramientas y datos independientes, no comerciales, que no están asociados ni respaldados por Airbnb ni por ninguno de los competidores de Airbnb.

Sin embargo, la información proporcionada por Dentro de Airbnb [19659003] no va a ser suficiente para nosotros. Vamos a descargar datos de allí para nuestro propio análisis.

Estaré trabajando con Toronto data . Porque vivo aquí y conozco algunos de los barrios aquí. Le invitamos a elegir la ciudad que prefiera.

Vamos a ver los listados y calendarios de Airbnb, y trataremos de proporcionar un análisis exploratorio para predecir los precios de los listados, tanto si estuviéramos trabajando hipotéticamente en Airbnb como también para un consumidor. ¡Comencemos!

Calendario

 calendario = pd.read_csv (& # 039; calendar.csv.gz & # 039;) 
 imprimir (& # 039; Tenemos & # 039 ;, calendar.date.nunique (), & # 039; días y & # 039 ;, calendar.listing_id.nunique (), & # 039; listados únicos en los datos del calendario. & # 039;)
 calendar.date.min (), calendar. date.max ()

El calendario cubre un período de tiempo del año, es decir, el precio y la disponibilidad todos los días durante el próximo año. En nuestro caso, de 2018–10–16 a 2019–10–15.

Figura 1

Disponibilidad en el calendario

Cuando miramos los datos del calendario, es posible que queramos hacer preguntas como: qué tan ocupado estará ¿Será para los anfitriones de Airbnb en Toronto el próximo año?

 calendar.available.value_counts ()

f (falso) significa que no está disponible, t (verdadero) significa que está disponible. Para averiguar la disponibilidad promedio diaria para un año, convertiremos la columna disponible a 0 si está disponible y 1 si no.

 calendar_new = calendar [['date', 'available']] 
 calendar_new ['busy'] = calendar_new.available.map (lambda x : 0 si x == & # 039; t & # 039; else 1) 
 calendar_new = calendar_new.groupby (& # 039; date & # 039;) ['busy'] .mean (). Reset_index () 
 calendar_new ['date'] = pd.to_datetime (calendar_new ['date'])
 plt.figure (figsize = (10, 5)) 
 plt.plot (calendar_new ['date']calendar_new ['busy']) 
 plt. title (& # 039; Airbnb Toronto Calendar & # 039;) 
 plt.ylabel (& # 039;% busy & # 039;) 
 plt.show ();
Figura 2

El mes más ocupado en Toronto fue octubre que acaba de pasar. Los próximos meses ocupados parecen después de abril y se extienden hasta el verano. Todo esto está dentro de nuestra experiencia y expectativas.

Precio en el calendario

¿Cómo cambian los precios a lo largo del año por mes?

Eliminamos el símbolo “$” en la columna de precios y lo convertimos en numérico, y convertimos la fecha en datetime data type.

 calendar ['date'] = pd.to_datetime (calendar ['date']) 
 calendar ['price'] = calendar ['price'] .str.replace (& # 039;, & # 039 ;, & # 039; & # 039;) 
 calendar ['price'] = calendar ['price'] .str.replace (& # 039; $ & # 039 ;, & # 039; & # 039;) 
 calendar ['price'] = calendar ['price'] .astype (float) 
 calendar ['date'] = pd.to_datetime (calendar ['date']) 
 mean_of_month = calendar.groupby (calendar ['date'] .dt.strftime (& # 039;% B & # 039;), 
 sort = False) ['price'] .mean () 
 mean_of_month.plot (kind = & # 039; barh & # 039;, figsize = (12,7)) 
 plt .xlabel (& # 039; precio mensual promedio & # 039;);
Figura 3

El precio de Airbnb en Toronto aumenta en los meses de Julio, agosto y octubre. De acuerdo, estos tres meses son los mejores meses para visitar Toronto.

¿Cómo cambian los precios durante el día de la semana?

 calendar ['dayofweek'] = calendar.date.dt.weekday_name 
 cats = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
 price_week = calendar [['dayofweek','price']] 
 price_week = calendar.groupby (['dayofweek']). Mean (). Reindex (cats) 
 price_week.drop (& # 039; listing_id & # 039 ;, axis = 1, inplace = True) 
 price_week.plot () 
 ticks = list (range (0, 7, 1)) # puntos en el eje x donde desea que aparezca la etiqueta 
 labels = "Mon Tues Weds Thurs Fri Sat Sun" .split () 
 plt.xticks (ticks, etiquetas);
Figura 4

Los viernes y sábados cuestan más de $ 10 que el resto de la semana.

Listas

Número de listados en cada vecindario

 listados = pd.read_csv (& # 039; Listings.csv.gz & # 039;) 
 print (& # 039; Tenemos & # 039 ;, Listings.id.nunique (), & # 039; listados en los datos del listado. & # 039;)
 lists.groupby (by = & # 039; neighbourhood_cleansed & # 03 9;). Count () [['id']]. Sort_values ​​(by = & # 039; id & # 039 ;, ascendente = False) .head (10)
Figura 5

El vecindario que tiene el mayor número de Los listados son Waterfront Communities-The Island, y casi cuatro veces más que el segundo vecindario más (Niagara). En el mapa de encabezado anterior, también podemos ver eso.

Revisar puntuación

 plt.figure (figsize = (12,6)) 
 sns.distplot (Listings.review_scores_rating. dropna (), rug = True) 
 sns.despine () 
 plt.show ();
Figura 6
 Listings.review_scores_rating.describe ()
Figura 7

Como se esperaba , la mayoría de los revisores dejan puntuaciones altas.

Explorando el precio

La columna de precios necesita una limpieza, como eliminar “$” y convertir a numérica.

 listados ['price'] = listados ['price'] .str.replace (& # 039;, & # 039;, & # 039; & # 039;) 
 listados ['price'] = listados ['price'] .str.replace (& # 039; $ & # 039 ;, & # 039 ; & # 039;) 
 listados ['price'] = listados ['price'] .astype (flotador)
 listados ['price'] .describe ()
Figura 8

El listado más caro de Airbnb en Toronto es $ 12933 / noche. De la lista de url parece legítimo por lo que puedo decir. El ático de un coleccionista de arte en el barrio más elegante de Toronto. ¡Agradable!

fuente: Airbnb

Para no ser afectado por los casos extremos, decidí eliminar los listados que excedan los $ 600 / noche, así como los 7 listados al precio 0, para el siguiente análisis exploratorio. [19659008] Lista la distribución de precios después de eliminar los valores atípicos

 Listings.loc [(Listingsprice 0)]. Price.hist (bins = 200) 
 plt.ylabel (& # 039; Cuenta & # 039;) 
 plt.xlabel (& # 039; Precio de listado en $ & # 039;) 
 plt.title (& # 039; Histograma de los precios de listado & # 039;);
Figura 9

Vecindad vs. Precio

 

Figura 10

No solo Waterfront Communities-The Island tiene el mayor número de listados, también disfruta del precio mediano más alto, y Milliken tiene el precio mediano más bajo.

tipo de propiedad vs. precio

 

Figure 11

Cuando nosotros Mire el precio promedio para cada tipo de propiedad, debemos tener cuidado de no poder decir “El tipo de propiedad más caro es el Aparthotel, y la Tienda y el Espacio de estacionamiento tienen un precio medio más alto que el de Apartamento y Castillo”, porque Aparthotel , Tend y Estacionamiento solo tienen una lista cada una. tipo de habitación vs. precio  

Figura 12

, toda la habitación / apt tiene un precio medio mucho más alto que los otros tipos de habitaciones.

 Listings.loc [(Listingsprice 0)]. pivot (columnas = & # 039; room_type & # 039 ;, values ​​= & # 039; price & # 039;). Plot.hist (stacked = True, bins = 100) 
 plt.xlabel (& # 039; Precio de listado en $ & # 039;);
Figura 13 [19659025] Toda la casa / apt también tiene el mayor número de listados. Dentro de Airbnb, se ha indicado que Las casas o apartamentos completos disponibles durante todo el año para turistas, probablemente no tienen el propietario presente, podrían ser ilegales y, lo que es más importante, están desplazando a los residentes . Dejaremos de lado nuestras preocupaciones por el momento. tipo de cama vs. precio  

Figura 14

No hay ninguna sorpresa aquí .

Servicios

El campo de texto de servicios necesita una pequeña limpieza.

 Listings.amenities = lists.amenities.str.replace ("[{}]", ") .str. reemplace (& # 039; "& # 039 ;," ") 
 listados ['amenities'] .head ()
Figura 15

Principales 20 servicios más comunes.

 pd .Series (np.concatenate (listados ['amenities'] .map (lambda amns: amns.split (",")))) [
 .value_counts (). Head (20)  
 .plot (kind = & # 039; barra & # 039;) 
 ax = plt.gca () 
 ax.set_xticklabels (ax.get_xticklabels (), rotación = 45, ha = & # 039; derecha & # 039 ;, fontsize = 12 ) 
 plt.show ();
Figura 16

Wifi, calefacción, esencial, cocina y detectores de humo, etc. se encuentran entre las comodidades más comunes.

Amenidades v precio top 20

 amenities = np.unique (np.concatenate (listados ['amenities'] .map (lambda amns: amns.split (",")))) 
 amenity_prices = [(amnlistados[listados['amenities'] .map (lambda amns: amn in amns)] ['price'] .mean ()) para amn en amenities if amn! = ""] 
 amenity_srs = pd.Series (data = [a[1] para a en amenity_prices]index = [a[0] para a en amenity_prices])
 amenity_srs.sort_values ​​(ascendiendo = False) [:20] .plot (kind = kind # & # 039; bar & # 039;) 
 ax = plt.gca () 
 ax.set_xticklabels (ax.get_xticklabels (), rotación = 45, ha = & # 039; derecha & # 039 ;, fontsize = 12) 
 plt.show ();
Figura 17

Esta interesante característica de servicios parece tener alguna relación con el precio.

Número de camas vs. precio

 Listings.loc [(Listingsprice 0)] .pivot (columnas = & # 039; camas & # 039;, valores = & # 039; precio & # 039;) plot.hist (apilado = Verdadero, contenedores = 100) 
 plt.xlabel (& # 039; Listing precio en $ & # 039;);
Figur e 18

La gran mayoría de los listados tienen una cama, el listado de una cama tiene una gama de precios muy amplia. Hay listados que no tienen cama.

 sns.boxplot (y = & # 039; price & # 039 ;, x = & # 039; beds & # 039 ;, data = Listings.loc [(Listingsprice 0)]) 
 plt.show ();
Figura 19

Es interesante descubrir que el precio mediano para los listados sin camas es mayor que los listados de 1 cama y 2 camas, y el precio mediano para 10 los listados de camas son muy bajos.

Características numéricas

Seleccionamos varias funciones numéricas e intentamos explorarlas todas juntas.

 col = ['host_listings_count', 'accommodates', 'bathrooms', 'bedrooms', 'beds', 'price', 'number_of_reviews', 'review_scores_rating', 'reviews_per_month']
 sns.set (style = "ticks" , color_codes = True) 
 sns.pairplot (Listings.loc [(Listingsprice 0)] [col] .dropna ()) 
 plt.show ();
Figure 20 [19659046] corr = Listings.loc [(Listingsprice 0)] [col] .dropna (). corr ()
plt.figure (figsize = (6,6))
sns.set ( font_scale = 1)
sns.heatmap (corr, cbar = True, annot = True, square = True, fmt = & # 039; .2f & # 039 ;, xticklabels = col, yticklabels = col)
plt. show ();

Figura 21 [19659025] Hay algunas noticias que no son malas, como el número de habitaciones y los alojamientos parecen estar relacionados con el precio. También se acomoda, las camas y las habitaciones están correlacionadas, guardaremos una de ellas para el modelo.

Precios de listado de modelos

Preprocesamiento de datos e ingeniería de características

Limpieza precio característica. La función que vamos a modelar y predecir.

 listados ['price'] = listados ['price'] .str.replace (& # 039;, & # 039 ;, & # 039; & # 039;) 
 listados ['price'] = listados ['price'] .str.replace (& # 039; $ & # 039 ;, & # 039; & # 039;) 
 listados ['price'] = listados ['price'] .astype (flotador) 
 Listings = Listings.loc [(Listingsprice 0)]

Matriz de documento de término para características de las características.

 

Reemplace los valores en la siguiente función a 0 si “f”, a 1 si “t”.

 columnas = ['host_is_superhost''host_identity_verified''host_has_profile_pic'
 & # 039; is_location_exact & # 039 ;, & # 039; require_license & # 039 ;, & # 039; instant_bookable & #pdf_actable_picable & # 039 ;, 19199017] # 039; require_guest_phone_verification & # 039;] 
 para c en columnas: 
 listados [c] = listados [c] .replace (& # 039; f & # 039;, 0, regex = True) 
 listados [c] = listados [c] .replace (& # 039; t & # 039;, 1 , regex = Verdadero)

La misma forma de limpiar las otras columnas de valor monetario.

 listados ['security_deposit'] = listados ['security_deposit'] .fillna (value = 0) 
 listados ['security_deposit'] = listados ['security_deposit'] .replace (& # 039; [$,)] & # 039;, & # 039; & # 039 ;, regex = True) .astype (float) 
 listados ['cleaning_fee'] = listados ['cleaning_fee'] .fillna (value = 0) 
 listados ['cleaning_fee'] = listados ['cleaning_fee'] .replace (& # 039; [$,)] & # 039;, & # 039; & # 039 ;, regex = True) .astype (flotador)

Las siguientes son las características numéricas que usaremos.

 

Rellene los valores que faltan en las características numéricas con la característica de

. para col en Listings_new.columns [listings_new.isnull().any()]:
Listings_new [col] = Listings_new [col] .fillna (Listings_new [col] .median ())

Procesando y agregando ing categorical features.

 para cat_feature in ['zipcode', 'property_type', 'room_type', 'cancellation_policy', 'neighbourhood_cleansed', 'bed_type']: 
 Listings_new = pd.concat ([listings_new, pd.get_dummies(listings[cat_feature])]axis = 1)

Agregar matrices de documento de plazo que creamos anteriormente de la función de servicios.

 Listings_new = pd.concat ([listings_new, df_amenities]axis = 1, join = & # 039; inner & # 039;)

Preprocesamiento de datos e ingeniería de características realizada

Regresor de bosques aleatorios

 

Característica de la importancia de los grupos de actividades de los grupos de animales de la naturaleza (194590020) columnas
coefs_df [‘coefs’] = rf.feature_importances_
coefs_df.sort_values ​​(& # 039; coefs & # 039 ;, ascendente = Falso) [19659181] Figura 22

Luz de la tarde [19659181]

Importancia de la función de LightGBM

índice 19/990202d804/href

Característica de LightGBM

 index.p.p.Cons. mayor (20) .plot (kind = & # 039; barh & # 039 ;, figsize = (10,6))
Figura 23

La importancia de la característica que producen estos dos modelos es similar.

Entonces, el mejor resultado que obtuvimos fue menos de 60 dólares de error RMSE, por lightGBM.

El cuaderno Jupyter se puede encontrar en Github . Disfrute el resto de la semana.

Dejá un comentario