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) |
-¿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?
Estadísticas básicas
Análisis univariante:
Análisis bivariante:
Análisis multivariante:
Análisis de correlación precio y tipo de habitación:
#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`
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)
#summary (df)
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"
Sobre el resumen de precios de alquiler de AirBnB en Barcelona:
Min. : 69.59: El precio mínimo de alquiler es de 69.59 euros.
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.
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.
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.
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.
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:
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.
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.
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:
Conclusiones y puntos relevantes:
Calidad: La alta calificación de limpieza y satisfacción general de los huéspedes sugiere que la mayoría de los alquileres de AirBnB en Barcelona ofrecen una buena experiencia al cliente.
Ubicación: Aunque la distancia media al área principal es de más de 2 km, la proximidad a las estaciones de metro sugiere que muchos de estos alojamientos son accesibles a través del transporte público.
Tamaño y capacidad: La mayoría de los alquileres parecen ser ideales para parejas o individuos viajando solos, con una capacidad de 2 y 1 dormitorio. Sin embargo, hay opciones disponibles para grupos más grandes.
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.
# 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))
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)
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()
# 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
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.
Diagonal principal: Esta diagonal (de la esquina superior izquierda a la esquina inferior derecha) siempre mostrará una correlación perfecta (valor de 1), ya que cualquier variable estará perfectamente correlacionada consigo misma.
Valores cercanos a 1 o -1: Estos valores indican una fuerte correlación positiva o negativa, respectivamente. En un heatmap, los colores (por lo general, una transición de colores fríos a cálidos) indican la fuerza y dirección de la correlación.
Valores cercanos a 0: Indican una correlación débil o inexistente entre las variables.
Simetría: Dado que la matriz de correlación es simétrica, la mitad inferior y superior de la matriz mostrarán la misma información.
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:
Positividad: Dado que la correlación es positiva (es decir, 0.72 y no -0.72), esto significa que a medida que el ranking de limpieza aumenta (por ejemplo, un ambiente más limpio o mejores críticas de limpieza), la satisfacción general de los huéspedes también tiende a aumentar.
Fuerza: El valor 0.72 está bastante cerca de 1 en la escala de correlación, lo que sugiere una relación fuerte. Las correlaciones varían de -1 a 1, donde -1 indica una relación lineal negativa perfecta, 0 indica ninguna relación lineal y 1 indica una relación lineal positiva perfecta. Por lo tanto, 0.72 indica que hay una tendencia clara y fuerte: a medida que una de las variables aumenta, es probable que la otra también lo haga.
Practicalidad: Aunque 0.72 sugiere una fuerte relación estadística, es importante también considerar si esta relación tiene sentido práctico o significado en el contexto real. En este caso, tiene sentido que la satisfacción de los huéspedes sea mayor en lugares más limpios.
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
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 factor
room_type`.
Aquí está el análisis de los resultados:
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
.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
.room_type
, es 19081838 y para Residuals
es
78700.
room_type
en cuanto al precio.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:
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.
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.
Outliers en cada 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.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.
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.
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.
El precio promedio de alquiler es 288.39 euros, pero hay una amplia dispersión en los precios, desde un mínimo de 69.59 euros hasta un máximo exorbitante de 6943.70 euros.
La mayoría de las propiedades (75%) se alquilan por menos de 335 euros. Sin embargo, algunos valores atípicos elevan significativamente el precio promedio.
La distribución de precios tiene un sesgo positivo, con la mayoría de los alquileres agrupados en el rango de precios más bajo y unos pocos valores atípicos extremadamente altos.
La capacidad promedio es de 2-3 personas, con la mayoría de las propiedades ideales para individuos o parejas viajando. Algunas alojan hasta 6 personas.
La calidad parece ser alta, con una calificación promedio de limpieza de 9/10 y satisfacción del huésped de 91/100.
La mayoría de las propiedades tienen 1 dormitorio y están razonablemente cerca de una estación de metro, sugiriendo una buena accesibilidad.
El tipo de habitación (entera, privada o compartida) tiene un impacto significativo en el precio. Alquilar alojamientos enteros es más costoso.
Dentro de cada categoría de habitación hay una variabilidad de precios considerable, con presencia de valores atípicos.
No se observan correlaciones fuertes entre precio y ubicación o calificaciones. La correlación más fuerte es entre limpieza y satisfacción del huésped.
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.