AirBnB Barcelona (días laborables)

Estadística descriptiva

Katia del Río



Fuente del dataset: https://www.kaggle.com/datasets/thedevastator/airbnb-prices-in-european-cities

CSV utilizado: barcelona_weekdays.csv

Este conjunto de datos ofrece una visión exhaustiva de los precios de Airbnb en Barcelona (días laborables). Cada anuncio se evalúa en base a los siguientes atributos:

Nombre de la columna Descripción
realSum El precio total del anuncio de Airbnb. (Numérico)
room_type El tipo de habitación que se ofrece (por ejemplo, privada, compartida, etc.). (Categórico)
room_shared Si la habitación es compartida o no. (Booleano)
room_private Si la habitación es privada o no. (Booleano)
person_capacity El número máximo de personas que pueden alojarse en la habitación. (Numérico)
host_is_superhost Si el anfitrión es un superanfitrión o no. (Booleano)
multi Si el anuncio es para varias habitaciones o no. (Booleano)
biz Si el anuncio es para fines de negocios o no. (Booleano)
cleanliness_rating La calificación de limpieza del anuncio. (Numérico)
guest_satisfaction_overall La calificación general de satisfacción de los huéspedes del anuncio. (Numérico)
bedrooms El número de dormitorios en el anuncio. (Numérico)
dist La distancia al centro de la ciudad. (Numérico)
metro_dist La distancia a la estación de metro más cercana. (Numérico)
lng La longitud del anuncio. (Numérico)
lat La latitud del anuncio. (Numérico)



Con este análisis se pretende dar respuesta a las siguientes preguntas:

-¿Cuál es el precio promedio de alquiler de Airbnb en Barcelona durante los días laborables?

-¿Cuál es la dispersión en los precios de alquiler observada?

-¿Cómo se distribuyen la mayoría de los precios de alquiler?

-¿Cuáles son las características más comunes de las propiedades listadas?

-¿Cómo es la calidad y satisfacción de los huéspedes?

-¿El tipo de habitación afecta significativamente el precio?

-¿Hay correlación entre precio y ubicación/calificaciones, tipo de habitacion?



Índice:

Estadísticas básicas

Análisis univariante:

Análisis bivariante:

Análisis multivariante:

Análisis de correlación precio y tipo de habitación:



Carga de los datos

#install.packages("readr")

library (readr)
## Warning: package 'readr' was built under R version 4.3.1
df <- read_csv("barcelona_weekdays.csv", show_col_types = FALSE)
## New names:
## • `` -> `...1`



Limpieza de Datos

head (df)
colnames(df)
##  [1] "...1"                       "realSum"                   
##  [3] "room_type"                  "room_shared"               
##  [5] "room_private"               "person_capacity"           
##  [7] "host_is_superhost"          "multi"                     
##  [9] "biz"                        "cleanliness_rating"        
## [11] "guest_satisfaction_overall" "bedrooms"                  
## [13] "dist"                       "metro_dist"                
## [15] "attr_index"                 "attr_index_norm"           
## [17] "rest_index"                 "rest_index_norm"           
## [19] "lng"                        "lat"



Eliminamos la primera columna porque no aporta información (Es un índice)

También podríamos eliminar todas las demás que no vamos a utilizar o simplemente dejarlas.

df <- subset(df, select = -`...1`)



Comprobamos si en el dataset hay valores no disponibles.

missing_data <- sort (colSums (is.na(df)), decreasing =TRUE)
missing_data <- missing_data [missing_data > 0]
missing_data
## named numeric(0)



También comprobamos si hay valores vacíos, en blanco.

colSums(df == "")
##                    realSum                  room_type 
##                          0                          0 
##                room_shared               room_private 
##                          0                          0 
##            person_capacity          host_is_superhost 
##                          0                          0 
##                      multi                        biz 
##                          0                          0 
##         cleanliness_rating guest_satisfaction_overall 
##                          0                          0 
##                   bedrooms                       dist 
##                          0                          0 
##                 metro_dist                 attr_index 
##                          0                          0 
##            attr_index_norm                 rest_index 
##                          0                          0 
##            rest_index_norm                        lng 
##                          0                          0 
##                        lat 
##                          0



Cambiar el nombre realSum por precio.

colnames(df)[colnames(df) == "realSum"] <- "precio"
#library(dplyr)
#df <- df %>% rename(realSum = precio)



Análisis Univariante

#summary (df)

Estadísticas generales

Elegimos las columnas de interés

library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.1
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
select(df, precio, person_capacity, cleanliness_rating, 
       guest_satisfaction_overall, bedrooms, dist, metro_dist) %>%
  summary()
##      precio        person_capacity cleanliness_rating
##  Min.   :  69.59   Min.   :2.000   Min.   : 2.000    
##  1st Qu.: 161.99   1st Qu.:2.000   1st Qu.: 9.000    
##  Median : 208.53   Median :2.000   Median :10.000    
##  Mean   : 288.39   Mean   :2.756   Mean   : 9.286    
##  3rd Qu.: 335.37   3rd Qu.:3.000   3rd Qu.:10.000    
##  Max.   :6943.70   Max.   :6.000   Max.   :10.000    
##  guest_satisfaction_overall    bedrooms          dist          metro_dist    
##  Min.   : 20.00             Min.   :0.000   Min.   :0.1199   Min.   :0.0130  
##  1st Qu.: 88.00             1st Qu.:1.000   1st Qu.:1.0906   1st Qu.:0.2521  
##  Median : 93.00             Median :1.000   Median :1.7518   Median :0.3705  
##  Mean   : 90.93             Mean   :1.217   Mean   :2.1173   Mean   :0.4349  
##  3rd Qu.: 97.00             3rd Qu.:1.000   3rd Qu.:2.9492   3rd Qu.:0.5542  
##  Max.   :100.00             Max.   :6.000   Max.   :8.4440   Max.   :2.4028
library(dplyr)

# Filtrar las filas donde bedrooms es 0
df_bedrooms_zero <- df %>%
  filter(bedrooms == 0)

# Ver los primeros registros del resultado
head(df_bedrooms_zero)
# Contar las filas donde bedrooms es 0
count_bedrooms_zero <- nrow(df_bedrooms_zero)

print(count_bedrooms_zero)
## [1] 31

Hay 31 filas en las que “Bedroms” es igual a 0, en principio no parece ser un error y podría tratarse de estudios o espacios abiertos.

# Función para calcular la moda
moda <- function(v) {
  tbl <- table(v)
  moda_vals <- as.numeric(names(tbl[tbl == max(tbl)]))
  return(moda_vals)
}

# Calcula la moda
moda_precio <- moda(df$precio)
moda_person_capacity <- moda(df$person_capacity)
moda_cleanliness_rating <- moda(df$cleanliness_rating)
moda_guest_satisfaction_overall <- moda(df$guest_satisfaction_overall)
moda_bedrooms <- moda(df$bedrooms)
moda_dist <- moda(df$dist)
moda_metro_dist <- moda(df$metro_dist)

# Calcula la desviación típica (standard deviation)
sd_precio <- sd(df$precio)
sd_person_capacity <- sd(df$person_capacity)
sd_cleanliness_rating <- sd(df$cleanliness_rating)
sd_guest_satisfaction_overall <- sd(df$guest_satisfaction_overall)
sd_bedrooms <- sd(df$bedrooms)
sd_dist <- sd(df$dist)
sd_metro_dist <- sd(df$metro_dist)

# Calcula la varianza
var_precio <- var(df$precio)
var_person_capacity <- var(df$person_capacity)
var_cleanliness_rating <- var(df$cleanliness_rating)
var_guest_satisfaction_overall <- var(df$guest_satisfaction_overall)
var_bedrooms <- var(df$bedrooms)
var_dist <- var(df$dist)
var_metro_dist <- var(df$metro_dist)
print(paste("Moda de precio ", moda_precio))
## [1] "Moda de precio  196.895291735518"
print(paste("Desviación típica de precio ", sd_precio))
## [1] "Desviación típica de precio  321.180435250841"
print(paste("Varianza de precio: ", var_precio))
## [1] "Varianza de precio:  103156.87198792"
print(paste("Moda de person_capacity: ", moda_person_capacity))
## [1] "Moda de person_capacity:  2"
print(paste("Desviación típica de person_capacityo ", sd_person_capacity))
## [1] "Desviación típica de person_capacityo  1.27661532836941"
print(paste("Varianza de person_capacity: ", var_person_capacity))
## [1] "Varianza de person_capacity:  1.62974669662773"
print(paste("Moda de cleanliness_rating : ", moda_cleanliness_rating))
## [1] "Moda de cleanliness_rating :  10"
print(paste("Desviación cleanliness_rating  ", sd_cleanliness_rating))
## [1] "Desviación cleanliness_rating   1.00744475796287"
print(paste("Varianza de cleanliness_rating : ", var_cleanliness_rating))
## [1] "Varianza de cleanliness_rating :  1.01494494034687"
print(paste("Moda de guest_satisfaction_overall: ", 
            moda_guest_satisfaction_overall))
## [1] "Moda de guest_satisfaction_overall:  100"
print(paste("Desviación guest_satisfaction_overall:  ", 
            sd_guest_satisfaction_overall))
## [1] "Desviación guest_satisfaction_overall:   8.69570740746789"
print(paste("Varianza de guest_satisfaction_overall: ", 
            var_guest_satisfaction_overall))
## [1] "Varianza de guest_satisfaction_overall:  75.615327316292"
print(paste("Moda de bedrooms : ", moda_bedrooms))
## [1] "Moda de bedrooms :  1"
print(paste("Desviación bedrooms  ", sd_bedrooms))
## [1] "Desviación bedrooms   0.569475177403005"
print(paste("Varianza de bedrooms : ", var_bedrooms))
## [1] "Varianza de bedrooms :  0.324301977678183"
print(paste("Desviación dist  ", sd_dist))
## [1] "Desviación dist   1.35151740678531"
print(paste("Varianza de dist : ", var_dist))
## [1] "Varianza de dist :  1.8265993008437"
print(paste("Desviación metro_dist  ", sd_metro_dist))
## [1] "Desviación metro_dist   0.275845835982257"
print(paste("Varianza de metro_dist : ", var_metro_dist))
## [1] "Varianza de metro_dist :  0.0760909252287502"



Primera observación:

Sobre el resumen de precios de alquiler de AirBnB en Barcelona:

  1. Min. : 69.59: El precio mínimo de alquiler es de 69.59 euros.

  2. 1st Qu.: 161.99: El 25% de los alquileres tiene un precio de hasta 161.99 euros. Esto es conocido como el primer cuartil y nos dice que un cuarto de las propiedades se alquilan por este precio o menos.

  3. Median : 208.53: La mediana es de 208.53 euros. Esto significa que la mitad de las propiedades se alquilan por menos de este precio y la otra mitad por más.

  4. Mean : 288.39: El precio promedio de alquiler es de 288.39 euros. Dado que el promedio es mayor que la mediana, esto sugiere que hay algunas propiedades que se alquilan a un precio mucho más alto, lo que eleva el promedio. Esta suposición es confirmada por el valor máximo que veremos a continuación.

  5. 3rd Qu.: 335.37: El 75% de los alquileres tiene un precio de hasta 335.37 euros. Esto es conocido como el tercer cuartil. Significa que tres cuartos de las propiedades se alquilan por este precio o menos.

  6. Max. : 6943.70: El precio máximo de alquiler es de 6943.70 euros, lo cual es extremadamente alto en comparación con la mediana y el promedio.

Datos adicionales:

  1. Moda: 196.89: La moda es el valor que aparece con más frecuencia. Esto significa que el precio más común de alquiler es de 196.89 euros.

  2. Desviación típica: 321.18: La desviación típica mide cuánto varían los precios respecto al promedio/media. Una desviación de 321.18 euros indica una considerable variación en los precios de alquiler.

  3. Varianza: 103156.87: La varianza es otra medida de dispersión. Es el cuadrado de la desviación típica. Una varianza alta, como en este caso, también indica una gran dispersión en los datos.

Conclusión: El mercado de alquiler de AirBnB en Barcelona presenta una amplia variedad de precios, desde opciones más asequibles hasta propiedades que elevan el precio promedio. La mayoría de las propiedades (el 75%) se alquilan por menos de 335.37 euros, pero hay algunas propiedades que se alquilan a precios exorbitantes, llegando hasta 6943.70 euros. La amplia desviación típica y la varianza confirman esta amplia dispersión de precios.

Por otro lado, tenemos los siguientes datos:

  1. person_capacity (Capacidad de personas):
    • La mayoría de los alojamientos (la moda) tienen capacidad para 2 personas.
    • La capacidad media es ligeramente superior a 2, con un valor de 2.756
    • Hay propiedades que admiten hasta 6 personas, pero la dispersión (desviación típica) es de 1.27, lo que indica que la mayoría de las propiedades están cerca del promedio de capacidad de 2-3 personas.
  2. cleanliness_rating (Calificación de limpieza):
    • La calificación media de limpieza es 9.286 de 10, lo que indica que la mayoría de los alojamientos están bastante limpios.
    • La moda es 10, lo que significa que la calificación más común es perfecta.
    • Sin embargo, con una desviación típica de 1.007, hay alojamientos que han obtenido calificaciones mucho más bajas (el mínimo es 2).
  3. guest_satisfaction_overall (Satisfacción general de los huéspedes):
    • La satisfacción media de los huéspedes es alta, con 90.93 sobre 100.
    • La calificación más común (moda) es 100, lo que es una excelente señal para los alquileres de AirBnB en Barcelona.
    • Sin embargo, la desviación típica es de 8.69, lo que sugiere que hay algunas propiedades con calificaciones considerablemente más bajas.
  4. bedrooms (Dormitorios):
    • La mayoría de las propiedades (la moda) tienen 1 dormitorio.
    • Llama la atención el mínimo (0)
    • La desviación típica es de 0.569, por lo que la mayoría de las propiedades tienen alrededor de 1 dormitorio, aunque hay algunas con hasta 6.
  5. dist (Distancia):
    • La distancia media es de 2.1173, con una desviación típica de 1.35. Esto sugiere que hay una variedad de propiedades tanto cerca como lejos del centro.
  6. metro_dist (Distancia al metro más cercano):
    • La distancia media al metro más cercano es de 0.4349, lo que sugiere que la mayoría de las propiedades están razonablemente cerca de una estación de metro.
    • La desviación típica es de 0.2758, indicando que hay propiedades muy cerca de una estación de metro y otras un poco más lejos, pero en general están bastante centradas alrededor de la media.

Conclusiones y puntos relevantes:

El análisis sugiere que Barcelona ofrece una amplia gama de opciones de alquiler en AirBnB, desde alojamientos pequeños y acogedores hasta opciones más grandes, y la mayoría proporciona una experiencia de alta calidad a los huéspedes.

Distribución de los Precios

# Visualizar los dos gráficos en una fila
par(mfrow=c(1,2))

# Histograma del precio
hist(df$precio, main="Distribución de Precios", xlab="Precio", breaks=50, 
     col="skyblue", border="black")

# Boxplot del precio
boxplot(df$precio, main="Boxplot de Precios", ylab="Precio", col="yellow")

El histograma y el boxplot revelan que los precios de alquiler de AirBnB en Barcelona presentan un sesgo positivo. Es decir, la mayoría de los alquileres tienden a agruparse en el rango de precios más bajo, mientras que hay un pequeño número de propiedades con precios extremadamente altos, conocidos como “valores atípicos”. Estos valores extremos afectan la media, elevándola por encima de la mediana, indicando el sesgo hacia la derecha.

El histograma visualiza claramente esta concentración de alquileres en el rango más bajo con una cola que se extiende hacia valores más altos. El boxplot, por otro lado, proporciona una vista concisa de la distribución, mostrando un rango intercuartílico (IQR) estrecho, lo que indica que el 50% central de los datos está agrupado en un rango de precios más bajo. La mediana, representada por la línea dentro de la caja, está más cerca del primer cuartil, reflejando nuevamente el sesgo. Los puntos por encima del “bigote” superior del boxplot representan los valores atípicos, destacando esas propiedades con precios excepcionalmente altos.

En conjunto, ambos gráficos ofrecen una imagen coherente de una distribución de precios sesgada a la derecha, con unos pocos alquileres en Barcelona que tienen precios significativamente más altos que la mayoría.

Creación del Histograma y Boxplot con la Transformación Logarítmica:

Se aplica una transformación logarítmica base 10 a la columna precio. Esto significa que cada valor en la columna precio fue reemplazado por su logaritmo en base 10.

#install.packages("gridExtra")

library(ggplot2)
library(dplyr)
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.3.1
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
# Aplica el logaritmo a la columna precio
df$log_precio <- log10(df$precio)

# Crea el histograma
histogram <- ggplot(df, aes(x = log_precio)) +
  geom_histogram(fill = "skyblue", color = "black", bins = 50) +
  labs(title = "Histograma de Precios",
       x = "Log10 del Precio",
       y = "Frecuencia") +
  theme_minimal()

# Crea el boxplot
box_plot <- ggplot(df, aes(y = log_precio)) +
  geom_boxplot(width = 0.5, fill = "yellow", color = "black") +
  labs(title = "Boxplot de Precios",
       y = "Log10 del Precio",
       x = "") +
  theme_minimal()

# Muestra ambos gráficos uno al lado del otro
grid.arrange(histogram, box_plot, ncol = 2)



La transformación logarítmica es una técnica común utilizada en análisis de datos para “aplanar” distribuciones que son altamente sesgadas debido a la presencia de valores atípicos (outliers). Esta transformación tiene el efecto de acercar juntos los valores grandes y expandir valores pequeños, haciendo que los datos sean más manejables y las visualizaciones más informativas.

library(ggplot2)

# Diagrama de violín
ggplot(df, aes(x = "", y = precio)) + 
  geom_violin(fill="pink", color="black") +
  labs(title = "Diagrama de Violín de Precios", y = "Precio") +
  theme_minimal()

# Calcular la densidad del kernel
densidad_precio <- density(df$precio)

# Calcular la densidad del kernel
densidad_precio <- density(df$precio)

# Gráfico de la densidad del kernel
plot(densidad_precio, main="Densidad del Kernel para los Precios", 
     xlab="Precio", ylab="Densidad", col="blue", lwd=2, type="n")  


# Rellenar el área bajo la curva
polygon(c(min(densidad_precio$x), densidad_precio$x, max(densidad_precio$x)), 
        c(0, densidad_precio$y, 0), col="lightblue")  




# Dibujar la línea de densidad sobre el área rellenada
lines(densidad_precio, col="blue", lwd=2)

Un diagrama de violín es una combinación de un boxplot y una estimación de la densidad de kernel. Es útil para visualizar la distribución y la densidad de los datos. Muestra la densidad de los datos a lo largo de diferentes precios, ofreciendo otra perspectiva de la distribución de los datos.

Vamos a visualizar la densidad Kernel solo en los datos hasta 1000 euros.

library (ggplot2)
get_mode <- function(v) {
  uniqv <- unique(v)
  uniqv[which.max(tabulate(match(v, uniqv)))]
}

p_zoom <- ggplot(df, aes(x=precio)) + 
  #geom_density(fill="blue")
  geom_density(color="blue") +
  geom_vline(aes(xintercept=median(precio), color="Mediana"),
             linetype="dashed", lwd=1) +
  geom_vline(aes(xintercept=mean(precio), color="Media"), 
             linetype="dashed", lwd=1) +
  geom_vline(aes(xintercept=quantile(precio, 0.25), color="Q1"), 
             linetype="dashed", lwd=1) +
  geom_vline(aes(xintercept=quantile(precio, 0.75), color="Q3"), 
             linetype="dashed", lwd=1) +
  geom_vline(aes(xintercept=get_mode(precio), color="Moda"), 
             linetype="dashed", lwd=1) +
  scale_color_manual(values=c("Mediana"="red", "Media"="green", "Q1"="orange",
                              "Q3"="purple", "Moda"="blue")) +
  labs(title="Zoom 0-1000 euros", x="Precio", y="Densidad") +
  coord_cartesian(xlim=c(0, 1000)) +
  theme(legend.key.height = unit(2, 'line')) +  
  # Ajustar el tamaño de la leyenda
  guides(color=guide_legend(override.aes=list(linetype="solid", size=1.5))) 
# Líneas horizontales y tamaño ajustado

print(p_zoom)



Tipos de Habitaciones y Anfitriones Superhost:

par(mfrow=c(1,2), cex.axis=0.6)

# Gráfico de barras para room_type
roomTypeTable <- table(df$room_type)
barplot(roomTypeTable, main="Tipos de Habitación", ylab="Número de Listados", 
        col=c("lightblue", "purple"))

# Gráfico de pastel de host_is_superhost
superhostTable <- table(df$host_is_superhost)
pie(superhostTable, main="Superhosts", col=c("purple", "lightblue"))



Calificación de Limpieza y Satisfacción:

# Configurar un diseño de gráficos 1x2
par(mfrow=c(1,2))

# Histograma de cleanliness_rating
hist(df$cleanliness_rating, main=" Calificación de Limpieza", 
     xlab="Calificación", breaks=20, col="lightpink", border="black")

# Histograma de guest_satisfaction_overall
hist(df$guest_satisfaction_overall, main="Satisfacción del Huésped", 
     xlab="Calificación", breaks=20, col="lightcyan", border="black")

# Revertir configuración de gráficos a normal
par(mfrow=c(1,1))



Análisis bivariante

Distancia al Centro vs. Precio:

# Scatter plot entre dist y precio
plot(df$dist, df$precio, main="Distancia al Centro vs Precio", 
     xlab="Distancia al Centro", ylab="Precio", col="blue", pch=16)



Distancia a la Estación de Metro vs. Precio:

# Scatter plot entre metro_dist y precio
plot(df$metro_dist, df$precio, main="Distancia al Metro vs Precio", 
     xlab="Distancia al Metro", ylab="Precio", col="blue", pch=16)



Análisis Multivariante

Calificación de Limpieza vs. Satisfacción vs. Precio:

#install.packages("scatterplot3d")

library(scatterplot3d)

# Paleta de colores según los precios
colors <- colorRampPalette(c("blue", "yellow", "red"))(100)
col_breaks <- quantile(df$precio, probs = seq(0, 1, by = 0.01))
col_values <- colors[findInterval(df$precio, col_breaks)]

# Usamos la escala logarítmica para el eje Z
s3d <- scatterplot3d(df$cleanliness_rating, df$guest_satisfaction_overall, 
                     log1p(df$precio), 
                     main="Calificación de Limpieza vs Satisfacción vs Precio
                     (Escala Logarítmica en Precio)", 
                     xlab="Limpieza", ylab="Satisfacción", zlab=
                       "Log(Precio + 1)", 
                     color = col_values, pch=19)

# Añade una leyenda para la escala de colores
legend("topright", legend = round(quantile(df$precio, probs = 
                                             c(0.1, 0.5, 0.9)), 2), fill = 
         colorRampPalette(c("blue", "yellow", "red"))(3), title = "Precio")



Tipo de Habitación vs. Calificación de Limpieza vs. Satisfacción:

# Instala y carga el paquete ggplot2
#install.packages("ggplot2")
library(ggplot2)

# Boxplots múltiples
ggplot(df, aes(x=room_type, y=cleanliness_rating)) + 
  geom_boxplot(aes(fill=room_type)) + 
  labs(title="Tipo de Habitación vs Calificación de Limpieza") +
  theme_minimal()

ggplot(df, aes(x=room_type, y=guest_satisfaction_overall)) + 
  geom_boxplot(aes(fill=room_type)) + 
  labs(title="Tipo de Habitación vs Satisfacción") +
  theme_minimal()



Geolocalización vs. Precio vs. Tipo de Habitación:

#install.packages("RColorBrewer")

library(RColorBrewer)
# Install and load required packages
# install.packages("leaflet")
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.3.1
# Cargar el paquete leaflet
library(leaflet)

# Define puntos de corte para la paleta de colores
breaks <- c(min(df$precio), 100, 200, 500, 1000, max(df$precio))

# Define una paleta de colores basada en esos puntos de corte
colorpal <- colorBin(palette = "RdYlBu", domain = df$precio, bins = breaks, 
                     reverse = TRUE)

# Define una función para establecer diferentes marcadores según el tipo de 
#habitación
shapepal <- function(room_type) {
  ifelse(room_type == 'Private', 1, # Marcador circular para habitaciones
         #privadas
         ifelse(room_type == 'Shared', 2, 3) # Marcador triangular para 
         #habitaciones compartidas
  )
}

# Define una paleta de colores basada en el tipo de habitación
room_pal <- colorFactor(palette = c("green", "red"), domain = df$room_type)

# Usa esta paleta de colores en el mapa con un fondo de tonos grises
leaflet(data = df) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircleMarkers(
    lng = ~lng,
    lat = ~lat,
    color = ~room_pal(room_type), # Cambia el color según el tipo de habitación
    radius = ~sqrt(precio)/10,   # Cambia el tamaño del círculo según el precio
   
    stroke = FALSE,
    fillOpacity = 0.8,
    popup = ~paste("Precio: ", precio, "<br>Tipo: ", room_type)
  ) %>%
  setView(lng = mean(df$lng), lat = mean(df$lat), zoom = 13) %>%
  addLegend(
    pal = room_pal, 
    values = ~room_type, 
    position = "bottomright", 
    title = "Tipo de Habitación",
    opacity = 1
  )



Distribución geográfica:

Relación entre la ubicación (dos variables: latitud y longitud) y el precio

#install.packages("leaflet")
#install.packages("leaflet.extras")
#install.packages("RColorBrewer")

library(RColorBrewer)
library(leaflet)
library(leaflet.extras)
## Warning: package 'leaflet.extras' was built under R version 4.3.1
library(RColorBrewer)


# Puntos de corte para la paleta de colores
breaks <- c(min(df$precio), 161.99, 335.37, 595.44, max(df$precio))

# Paleta de colores basada en esos puntos de corte
colorpal <- colorBin(palette = "RdYlBu", domain = df$precio, bins = breaks, 
                     reverse = TRUE)


# Mapa con un fondo de tonos grises para una mejor visualización
library(leaflet)

leaflet(data = df) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircleMarkers(
    lng = ~lng,
    lat = ~lat,
    color = ~colorpal(precio),
    radius = 5,
    stroke = FALSE,
    fillOpacity = 2,
    popup = ~paste("Precio: ", precio)
  ) %>%
  setView(lng = mean(df$lng), lat = mean(df$lat), zoom = 13) %>%
  addLegend(
    pal = colorpal, 
    values = ~precio, 
    position = "bottomright", 
    title = "Precio",
    labFormat = labelFormat(suffix = " €"),
    opacity = 1
  )



Mapa de Calor Geográfico Basado en el Precio:

#install.packages("leaflet.extras")

library(leaflet)
library(leaflet.extras)

leaflet(df) %>%
  addTiles() %>%
  addHeatmap(lng = ~lng, lat = ~lat, intensity = ~precio, radius = 10,
             blur = 15, max = max(df$precio))



Diagrama de Dispersión de Precio vs. Satisfacción del Cliente:

library(ggplot2)

ggplot(df, aes(x=precio, y=guest_satisfaction_overall)) +
  geom_point(aes(color=guest_satisfaction_overall), alpha=0.5) +
  scale_color_gradient(low="blue", high="red") +
  labs(title="Precio vs. Satisfacción del Cliente", x="Precio", 
       y="Satisfacción del Cliente") +
  theme_minimal()



Correlación de Pearson entre variables cuantitativas

# Selecciona las columnas que te interesan
selected_columns <- df[, c("precio", "person_capacity", "cleanliness_rating", 
                           "guest_satisfaction_overall", "bedrooms", "dist", 
                           "metro_dist")]

# Calcula la matriz de correlación de Pearson
cor_matrix <- cor(selected_columns, method = "pearson", 
                  use = "pairwise.complete.obs")

print(cor_matrix)
##                                  precio person_capacity cleanliness_rating
## precio                      1.000000000      0.42578521       -0.005278299
## person_capacity             0.425785211      1.00000000       -0.074442971
## cleanliness_rating         -0.005278299     -0.07444297        1.000000000
## guest_satisfaction_overall -0.048451053     -0.14629878        0.720185242
## bedrooms                    0.410897993      0.74452770       -0.042873283
## dist                       -0.018332148     -0.03976698       -0.004326634
## metro_dist                 -0.015370191     -0.00454099       -0.023956573
##                            guest_satisfaction_overall    bedrooms         dist
## precio                                    -0.04845105  0.41089799 -0.018332148
## person_capacity                           -0.14629878  0.74452770 -0.039766980
## cleanliness_rating                         0.72018524 -0.04287328 -0.004326634
## guest_satisfaction_overall                 1.00000000 -0.08071854  0.011993403
## bedrooms                                  -0.08071854  1.00000000  0.024210055
## dist                                       0.01199340  0.02421005  1.000000000
## metro_dist                                 0.01240521  0.02294977  0.428311374
##                             metro_dist
## precio                     -0.01537019
## person_capacity            -0.00454099
## cleanliness_rating         -0.02395657
## guest_satisfaction_overall  0.01240521
## bedrooms                    0.02294977
## dist                        0.42831137
## metro_dist                  1.00000000
  1. Precio y capacidad de la persona (0.426):
    • Hay una correlación positiva moderada. Esto sugiere que, en general, a medida que el número de personas que una propiedad puede albergar aumenta, también lo hace el precio. Tiene sentido ya que propiedades más grandes, que pueden alojar a más personas, tienden a ser más caras.
  2. Precio y calificación de limpieza (-0.005):
    • Esta es una correlación muy débil y cercana a cero, lo que sugiere que no hay una relación lineal clara entre el precio y la calificación de limpieza.
  3. Precio y satisfacción general del cliente (-0.048):
    • Esta es una correlación negativa débil. Aunque es negativa, es muy cercana a cero, lo que sugiere que no hay una relación lineal fuerte entre el precio y la satisfacción general del cliente.
  4. Calificación de limpieza y satisfacción general del cliente (0.720):
    • Hay una correlación positiva fuerte. Esto significa que, en general, a medida que la calificación de limpieza aumenta, también lo hace la satisfacción general del cliente. Esto tiene sentido, ya que la limpieza es un factor importante para la satisfacción del cliente.
  5. Capacidad de la persona y dormitorios (0.745):
    • Hay una correlación positiva fuerte. Esto sugiere que las propiedades con más dormitorios tienden a poder alojar a más personas.
  6. Distancia al centro y distancia al metro (0.428):
    • Hay una correlación positiva moderada. Esto podría indicar que las propiedades que están más lejos del centro también tienden a estar más lejos de las estaciones de metro, aunque hay excepciones.

Los otros coeficientes de correlación en la matriz son bastante bajos, lo que sugiere que no hay una relación lineal fuerte entre esas variables.

Es importante recordar que estos valores sólo capturan relaciones lineales. Si hay relaciones no lineales, el coeficiente de correlación de Pearson podría no captarlas. Además, la correlación no implica causalidad. Por ejemplo, aunque hay una correlación fuerte entre la calificación de limpieza y la satisfacción del cliente, no podemos decir con certeza que una alta calificación de limpieza causa una alta satisfacción del cliente sin un análisis más detallado.

range(cor_matrix)
## [1] -0.1462988  1.0000000



Vamos a visualizar la correlación con un mapa de calor:

# Instala y carga el paquete gplots si aún no lo has hecho
if(!require(gplots)) {
  install.packages("gplots")
  library(gplots)
}
## Loading required package: gplots
## Warning: package 'gplots' was built under R version 4.3.1
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
# Dibuja el heatmap usando heatmap.2
heatmap.2(cor_matrix, 
          dendrogram = "none",
          Rowv = FALSE, 
          Colv = FALSE, 
          col = colorRampPalette(c("blue", "yellow", "red"))(25),
          trace = "none", 
          key = TRUE, 
          symm = TRUE,
          density.info = "none", 
          scale = "none", 
          labRow = rownames(cor_matrix), 
          labCol = colnames(cor_matrix), 
          cexRow = 0.7, 
          cexCol = 0.7,
          cellnote = round(cor_matrix, 2), # texto de las celdas
          notecol = "black"  # color del texto
)

El heatmap permite visualizar rápidamente las relaciones entre varias variables y identificar aquellas que pueden estar fuertemente correlacionadas (ya sea positiva o negativamente).El cálculo de correlaciones, como el coeficiente de correlación de Pearson, requiere que las variables sean numéricas. Esto se debe a que el coeficiente de correlación mide la relación lineal entre dos variables cuantitativas.

Una correlación de 0.72 entre el “ranking de limpieza” y “satisfacción” sugiere una relación lineal positiva fuerte entre estas dos variables. En otras palabras, a medida que una variable aumenta, la otra también tiende a aumentar, y esta relación es relativamente fuerte.

Interpretando este valor en el contexto proporcionado:

Es esencial recordar que la correlación no implica causalidad. Aunque estas dos variables están correlacionadas, no podemos decir con certeza que una limpieza mejorada causará automáticamente una mayor satisfacción en los huéspedes. Puede haber otras variables en juego o factores no observados que también contribuyan a la satisfacción del huésped.

Histograma precio promedio por tipo de alquiler

¿Cuánto contribuye el tipo de habitación al total del precio promedio?

# Carga las librerías necesarias
library(ggplot2)
library(dplyr)

# Cálculo del precio promedio para cada tipo de habitación
avg_price_data <- df %>%
  group_by(room_type) %>%
  summarise(AveragePrice = mean(precio, na.rm = TRUE)) %>%
  arrange(-AveragePrice)

# Gráfico de barras
ggplot(avg_price_data, aes(x = room_type, y = AveragePrice, fill = room_type)) +
  geom_bar(stat = "identity") +
  labs(title = "Precio Promedio por Tipo de Habitación",
       x = "Tipo de Habitación", y = "Precio Promedio") +
  theme_minimal() +
  theme(legend.position = "none")

library(dplyr)

summary_data <- df %>%
  group_by(room_type) %>%
  summarise(
    Average = mean(precio, na.rm = TRUE),
    Median = median(precio, na.rm = TRUE),
    Mode = as.numeric(names(sort(table(precio), decreasing = TRUE)[1])),
    Q1 = quantile(precio, 0.25, na.rm = TRUE),
    Q3 = quantile(precio, 0.75, na.rm = TRUE)
  )

print(summary_data)
## # A tibble: 3 × 6
##   room_type       Average Median  Mode    Q1    Q3
##   <chr>             <dbl>  <dbl> <dbl> <dbl> <dbl>
## 1 Entire home/apt    573.   474.  474. 384.   619.
## 2 Private room       203.   185.  197. 151.   229.
## 3 Shared room        115.   111.  111.  97.1  118.



Distribución del Precio según Tipo de Habitación

library(dplyr)

df %>%
  group_by(room_type) %>%
  summarise(average_price = mean(precio, na.rm = TRUE))
library(ggplot2)

ggplot(df, aes(x = room_type, y = precio)) +
  geom_boxplot() +
  labs(title = "Distribución del Precio según Tipo de Habitación", 
       x = "Tipo de Habitación", y = "Precio") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Para determinar dónde comienzan los valores atípicos en un boxplot, podemos usar la fórmula del “bigote” superior. Los valores que exceden el “bigote” superior se consideran valores atípicos. El límite superior del bigote se calcula de la siguiente manera:

\[ \text{Bigote superior} = Q3 + 1.5 \times \text{IQR} \]

Donde:

\[ \text{IQR (Rango Intercuartílico)} = Q3 - Q1 \]

Vamos a calcular el bigote superior para cada tipo de habitación usando el resumen que ya has obtenido:

library(dplyr)

# Tu código previo para obtener el resumen
summary_data <- df %>%
  group_by(room_type) %>%
  summarise(
    Average = mean(precio, na.rm = TRUE),
    Median = median(precio, na.rm = TRUE),
    Mode = as.numeric(names(sort(table(precio), decreasing = TRUE)[1])),
    Q1 = quantile(precio, 0.25, na.rm = TRUE),
    Q3 = quantile(precio, 0.75, na.rm = TRUE)
  )

# Calcular el IQR y el límite superior del bigote
summary_data <- summary_data %>%
  mutate(
    IQR = Q3 - Q1,
    Upper_Whisker = Q3 + 1.5 * IQR
  )

# Imprimir la tabla con el límite superior del bigote para cada tipo de habitación
print(select(summary_data, room_type, Upper_Whisker))
## # A tibble: 3 × 2
##   room_type       Upper_Whisker
##   <chr>                   <dbl>
## 1 Entire home/apt          971.
## 2 Private room             347.
## 3 Shared room              149.

Este código agregará una columna “Upper_Whisker”que muestra dónde comienza el valor atípico para cada tipo de habitación.

Para determinar qué tipo de habitación tiene más valores atípicos (outliers), primero necesitamos contar cuántos precios en df exceden el “bigote superior” (Upper Whisker) para cada tipo de habitación.

Contar valores atípicos para cada tipo de habitación y Calcular el porcentaje de valores atípicos respecto al total de cada tipo de habitación:

outliers_percentage <- df %>%
  group_by(room_type) %>%
  summarise(
    total_count = n(),
    outlier_count = sum(precio > ifelse(room_type == "Entire home/apt", 971.1523,
                                ifelse(room_type == "Private room", 347.2432, 149.4170))),
    percentage_outliers = (outlier_count / total_count) * 100
  )

print(outliers_percentage)
## # A tibble: 3 × 4
##   room_type       total_count outlier_count percentage_outliers
##   <chr>                 <int>         <int>               <dbl>
## 1 Entire home/apt         362            17                4.70
## 2 Private room           1185            59                4.98
## 3 Shared room               8             1               12.5



Prueba estadística ANOVA

Se realiza una prueba ANOVA para determinar si hay diferencias significativas en el precio entre las diferentes categorías de room_type.

anova_result <- aov(precio~ room_type, data = df)
summary(anova_result)
##               Df    Sum Sq  Mean Sq F value Pr(>F)    
## room_type      2  38163676 19081838   242.5 <2e-16 ***
## Residuals   1552 122142103    78700                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

El resultado de la prueba ANOVA que nos presentas está diseñado para investigar si hay diferencias significativas en las medias del precio (precio) entre los diferentes niveles del factorroom_type`.

Aquí está el análisis de los resultados:

  1. Df (Grados de Libertad):
    • room_type: Representa el número de niveles en la variable room_type menos uno. Aquí vemos un valor de 2, lo que indica que hay tres niveles o categorías en room_type.
    • Residuals: Representa los grados de libertad residuales. Estos son el número de observaciones menos el número de niveles de room_type.
  2. Sum Sq (Suma de Cuadrados):
    • room_type: Es la variabilidad total explicada por la variable room_type.
    • Residuals: Es la variabilidad que no puede ser explicada por la variable room_type.
  3. Mean Sq (Cuadrado Medio):
    • Es la Suma de Cuadrados dividida por los grados de libertad. Para room_type, es 19081838 y para Residuals es 78700.
  4. F value:
    • Es el valor estadístico F que es una medida de cuán significativas son las diferencias entre las medias de los grupos. En este caso, tiene un valor de 242.5, lo que es bastante alto, indicando que hay diferencias significativas entre los niveles de room_type en cuanto al precio.
  5. Pr(>F):
    • Es el p-valor asociado con la prueba F. Un p-valor muy pequeño (aquí es menor que 2e-16, es decir, extremadamente cercano a 0) indica que puedes rechazar la hipótesis nula de que las medias de precio son iguales para todos los niveles de room_type.

Dada la prueba ANOVA y el p-valor extremadamente pequeño, hay evidencia suficiente para rechazar la hipótesis nula de que no hay diferencia en las medias de precio entre las diferentes categorías de room_type. Esto significa que el tipo de habitación tiene un efecto significativo en el precio.

Basándonos en los datos proporcionados y en el análisis ANOVA, podemos sacar las siguientes conclusiones:

  1. Diferencias significativas en precios: La prueba ANOVA ha demostrado que hay diferencias significativas en los precios de alquiler entre los diferentes tipos de habitaciones. Específicamente, el valor F extremadamente alto y el p-valor muy cercano a cero indican que las diferencias en las medias de precios entre las categorías de room_type no se deben simplemente a la variación aleatoria.

  2. Entire home/apt tiene precios más altos: Observando el límite superior del bigote (Upper Whisker) en los datos de los boxplots, la categoría Entire home/apt tiene el valor más alto (971.1523), lo que indica que alquilar una casa o apartamento completo tiende a ser más costoso que las otras categorías. Esto tiene sentido, ya que alquilar una propiedad completa suele ofrecer más espacio y comodidades que una habitación individual o compartida.

  3. Outliers en cada categoría:

    • La categoría Entire home/apt tiene 17 propiedades que exceden el valor de 971.1523, lo que representa un 4.696133% de su total.
    • Private room tiene 59 propiedades que superan el valor de 347.2432, lo que representa un 4.978903% del total en esa categoría.
    • Shared room, aunque solo tiene 8 propiedades en total, tiene 1 propiedad que excede el valor de 149.4170, es decir, un 12.5% de esa categoría.
  4. Número de outliers en relación con el total: Aunque el porcentaje más alto de outliers está en la categoría Shared room (12.5%), hay que tener en cuenta que esta categoría tiene un número total muy bajo de propiedades (solo 8). Esto significa que incluso un pequeño número de outliers puede dar lugar a un alto porcentaje. En términos absolutos, la categoría Private room tiene el mayor número de outliers (59), seguido por Entire home/apt con 17.

  5. Implicaciones del mercado: Estos datos sugieren que, aunque en general se espera que alquilar una casa o apartamento completo sea más costoso, también hay una variabilidad considerable en las tarifas de alquiler dentro de cada categoría, especialmente en las habitaciones privadas. Estos valores atípicos pueden ser propiedades premium o ubicadas en áreas particularmente deseables de la ciudad.



Conclusión final:

En el mercado de alquiler de AirBnB en Barcelona, el tipo de habitación tiene un impacto significativo en el precio, siendo las propiedades completas las más caras. Sin embargo, hay una variabilidad considerable en las tarifas dentro de cada categoría, con una notable cantidad de outliers, especialmente en las habitaciones privadas. Estas propiedades atípicas pueden influir en las expectativas del mercado y deberían ser consideradas por aquellos que buscan alquilar o listar propiedades en la plataforma.

En resumen, Barcelona ofrece una amplia variedad de opciones de alquiler en Airbnb, con una buena relación calidad-precio en la mayoría de las propiedades, pero con precios muy variables entre categorías y la presencia notable de valores atípicos por encima del rango típico.