Cargamos la base de datos ya limpia para poder emplearla en nuestro objetivo:
Valencia_Sale <- readRDS("base_2018_limpia.Rds")
Para poder estudiar las variables que influyen sobre cada piso dependiendo del barrio en el que se encuentre, deberemos de seguir diversos pasos que nos llevarán a poder conseguirlo.
Primeramente, agruparemos los barrios en distritos -> En Valencia hay más de 80 barrios, pero solo 19 distritos. Usar distritos reduce la complejidad y mejora la visualización y comunicación de resultados.
Además, los distritos son divisiones oficiales del ayuntamiento de Valencia, utilizadas en censos, estadísticas urbanas, presupuestos municipales, etc. Seguir esta estructura permite que nuestros análisis sean comparables con fuentes oficiales.
Valencia_Sale$BARRIO <- as.character(Valencia_Sale$BARRIO)
# barrios_unicos <- unique(Valencia_Sale$BARRIO) para poder saber todos los barrios que tenemos
# los distritos los sacamos directamente de la web de Idealista
distritos <- c(
"Extramurs", "Ciutat Vella", "L'Eixample", "Benicalap", "Patraix", "Campanar",
"Quatre Carreres", "El Pla del Real", "Rascanya", "Benimaclet", "L'Olivereta", "Jesús",
"La Saïdia", "Camins al Grau", "Poblats Marítims", "Algirós", "La Patacona", "Alboraya Centro")
# le asignamos a cada barrio su distrito correspondiente, basándonos en la división administrativa oficial de Valencia
barrio_distrito <- c(
# Ciutat Vella
"LA SEU" = "Ciutat Vella", "LA XEREA" = "Ciutat Vella", "EL CARME" = "Ciutat Vella",
"EL MERCAT" = "Ciutat Vella", "EL PILAR" = "Ciutat Vella", "SANT FRANCESC" = "Ciutat Vella",
# L'Eixample
"RUSSAFA" = "L'Eixample", "LA GRAN VIA" = "L'Eixample", "EL PLA DEL REMEI" = "L'Eixample",
# Extramurs
"EL BOTANIC" = "Extramurs", "LA ROQUETA" = "Extramurs", "LA PETXINA" = "Extramurs", "ARRANCAPINS" = "Extramurs",
# Campanar
"CAMPANAR" = "Campanar", "SANT PAU" = "Campanar", "LES TENDETES" = "Campanar",
# La Saïdia
"EL CALVARI" = "La Saïdia", "MARXALENES" = "La Saïdia", "MORVEDRE" = "La Saïdia",
"TRINITAT" = "La Saïdia", "ELS ORRIOLS" = "La Saïdia", "TORMOS" = "La Saïdia",
# El Pla del Real
"EXPOSICIO" = "El Pla del Real", "MESTALLA" = "El Pla del Real",
"JAUME ROIG" = "El Pla del Real", "CIUTAT UNIVERSITARIA" = "El Pla del Real",
# L'Olivereta
"NOU MOLES" = "L'Olivereta", "TRES FORQUES" = "L'Olivereta", "LA FONTSANTA" = "L'Olivereta",
"LA LLUM" = "L'Olivereta", "SOTERNES" = "L'Olivereta",
# Patraix
"PATRAIX" = "Patraix", "SAFRANAR" = "Patraix", "SANT ISIDRE" = "Patraix",
"LA RAIOSA" = "Patraix", "L'HORT DE SENABRE" = "Patraix", "FAVARA" = "Patraix",
"FAITANAR" = "Patraix", "VARA DE QUART" = "Patraix",
# Jesús
"LA CREU COBERTA" = "Jesús", "SANT MARCEL.LI" = "Jesús", "CAMI REAL" = "Jesús",
# Quatre Carreres
"MONTOLIVET" = "Quatre Carreres", "NA ROVELLA" = "Quatre Carreres", "EN CORTS" = "Quatre Carreres",
"MALILLA" = "Quatre Carreres", "LA PUNTA" = "Quatre Carreres",
"CIUTAT DE LES ARTS I DE LES CIENCIES" = "Quatre Carreres", "LA FONTETA S.LLUIS" = "Quatre Carreres",
# Poblats Marítims
"EL GRAU" = "Poblats Marítims", "AIORA" = "Poblats Marítims", "CABANYAL-CANYAMELAR" = "Poblats Marítims",
"LA MALVA-ROSA" = "Poblats Marítims", "BETERO" = "Poblats Marítims", "LA CREU DEL GRAU" = "Poblats Marítims",
"NATZARET" = "Poblats Marítims",
# Camins al Grau
"CAMI FONDO" = "Camins al Grau", "PENYA-ROJA" = "Camins al Grau", "LA VEGA BAIXA" = "Camins al Grau",
# Algirós
"L'AMISTAT" = "Algirós", "ALBORS" = "Algirós", "CIUTAT JARDI" = "Algirós",
"L'ILLA PERDUDA" = "Algirós", "LA CARRASCA" = "Algirós",
# Benimaclet
"BENIMACLET" = "Benimaclet", "CAMI DE VERA" = "Benimaclet",
# Rascanya
"SANT LLORENS" = "Rascanya", "TORREFIEL" = "Rascanya", "SANT ANTONI" = "Rascanya",
# Benicalap
"BENICALAP" = "Benicalap", "CIUTAT FALLERA" = "Benicalap", "BENIFERRI" = "Benicalap",
"POBLE NOU" = "Benicalap",
# La Patacona / Alboraya
"LA PATACONA" = "La Patacona",
"ALBORAIA CENTRO" = "Alboraya Centro"
)
Valencia_Sale <- Valencia_Sale %>%
mutate(DISTRITO = recode(BARRIO, !!!barrio_distrito))
Valencia_Sale$DISTRITO <- as.character(Valencia_Sale$DISTRITO) # pasamos la columna a tipo texto
sum(is.na(Valencia_Sale$DISTRITO)) # ver el número de pisos faltantes, sin distrito asignado
## [1] 0
Hemos asignado a cada barrio su distrito correspondiente. Asimismo, hemos comprobado que no hay ningún piso que no tenga un distrito asignado (no hay valores faltantes).
Posteriormente, para facilitar nuestro análisis crearemos una nueva variable RANGO_PRECIO, que clasifique las viviendas en 3 tipos, Barato-Medio-Caro.
De esta forma nos será más fácil determinar que características presentan los pisos de cada distrito dependiendo del RANGO_PRECIO donde se encuentren.
hist(Valencia_Sale$PRICE,
breaks = 30, # Número de barras (puedes ajustar)
col = "skyblue", # Color de las barras
border = "white", # Color del borde de las barras
main = "Histograma de precios de viviendas en Valencia 2018",
xlab = "Precio (€)",
ylab = "Frecuencia")
summary(Valencia_Sale$PRICE)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24000 97000 148000 195036 228000 2772000
Después de haber analizado minuciosamente el histograma y el resumen estadístico de la variable PRICE, hemos decidido dividir los rangos de precio de la siguiente forma:
Se ajusta aproximadamente al 1er cuartil (97.000 €). Es más, el histograma muestra una enorme acumulación de viviendas con precios por debajo de 100.000 €.
Incluye las viviendas más accesibles del mercado.
Aquí se concentra la mayor parte del mercado, y donde el volumen comienza a caer gradualmente a partir de los 300k€. Cubre el rango entre el 1er y algo más allá del 3er cuartil (228.000 €).
Incluye la mediana (148.000 €) y la mayoría del stock disponible.
Refleja el mercado “normal” o promedio.
Representa pisos por encima del rango común.
A partir de los 300.000 €, la frecuencia en el histograma cae en picado. Es un indicio claro de que estamos entrando en el segmento de lujo o alto standing.
Hemos discretizado la variable de precios.
Valencia_Sale$RANGO_PRECIO <- cut(
Valencia_Sale$PRICE,
breaks = c(-Inf, 100000, 300000, Inf),
labels = c("Barato", "Medio", "Caro"),
right = TRUE
)
table(Valencia_Sale$RANGO_PRECIO)
##
## Barato Medio Caro
## 7299 16076 3944
library(dplyr)
conteo_distrito2 <- Valencia_Sale %>%
group_by(DISTRITO) %>%
summarise(
Barato = sum(RANGO_PRECIO == "Barato", na.rm = TRUE),
Medio = sum(RANGO_PRECIO == "Medio", na.rm = TRUE),
Caro = sum(RANGO_PRECIO == "Caro", na.rm = TRUE)
) %>%
arrange(DISTRITO)
print(conteo_distrito2)
## Simple feature collection with 16 features and 4 fields
## Geometry type: MULTIPOINT
## Dimension: XY
## Bounding box: xmin: -0.4207006 ymin: 39.43827 xmax: -0.3201343 ymax: 39.50368
## Geodetic CRS: WGS 84
## # A tibble: 16 × 5
## DISTRITO Barato Medio Caro geometry
## <chr> <int> <int> <int> <MULTIPOINT [°]>
## 1 Algirós 180 692 26 ((-0.3362106 39.46647), (-0.3369327 39.4…
## 2 Benicalap 940 819 66 ((-0.4071434 39.49341), (-0.4071621 39.4…
## 3 Benimaclet 69 481 65 ((-0.3693014 39.4865), (-0.3691448 39.48…
## 4 Camins al Grau 40 320 258 ((-0.347168 39.47542), (-0.3479445 39.47…
## 5 Campanar 100 579 277 ((-0.4180671 39.4942), (-0.4183555 39.49…
## 6 Ciutat Vella 50 1109 950 ((-0.3723386 39.47809), (-0.3744231 39.4…
## 7 El Pla del Real 18 489 480 ((-0.3560063 39.46856), (-0.3559592 39.4…
## 8 Extramurs 97 1695 368 ((-0.3820533 39.45587), (-0.3819296 39.4…
## 9 Jesús 466 329 5 ((-0.3865202 39.44363), (-0.3864282 39.4…
## 10 L'Eixample 23 1009 1011 ((-0.3665549 39.4724), (-0.3662847 39.47…
## 11 L'Olivereta 845 1099 18 ((-0.4090213 39.46351), (-0.4098033 39.4…
## 12 La Saïdia 1146 1086 80 ((-0.3891738 39.48858), (-0.3894098 39.4…
## 13 Patraix 822 2083 38 ((-0.407236 39.45055), (-0.4044056 39.45…
## 14 Poblats Marítims 1068 1768 77 ((-0.3226582 39.46345), (-0.3267495 39.4…
## 15 Quatre Carreres 651 1789 137 ((-0.335995 39.44653), (-0.335852 39.446…
## 16 Rascanya 784 729 88 ((-0.3770805 39.49883), (-0.3752335 39.4…
-> Distritos con mayoría de pisos baratos:
La Saïdia (1146), Poblats Marítims (1068), Benicalap (940) y L’Olivereta (845) tienen una gran cantidad de pisos de bajo coste. Son zonas con una importante oferta de vivienda económica.
-> Distritos con mayoría de pisos medios:
Patraix (2083), Quatre Carreres (1789), Poblats Marítims (1768), Extramurs (1695) y L’Eixample (1009) presentan una alta concentración en el segmento medio, indicando posiblemente una mezcla equilibrada de calidad, ubicación y accesibilidad.
-> Distritos con abundancia de pisos caros:
L’Eixample (1011), Ciutat Vella (950) y El Pla del Real (480) destacan por una elevada cantidad de viviendas caras, lo que podría reflejar zonas de prestigio y/o céntricas.
-> Zonas con mayor mezcla de precios
Distritos donde encontramos una presencia importante de los tres rangos (Barato, Medio, Caro):
Camins al Grau, Campanar, Benimaclet, Poblats Marítims y Rascanya muestran una variedad de precios, esto se traduce en que podemos encontrar pisos para cualquier bolsillo y presupuesto.
-> Distritos con perfil de alta gama
L’Eixample y Ciutat Vella destacan por tener más pisos caros que baratos, y una gran cantidad también de pisos de gama media, lo que indica una tendencia hacia el lujo o viviendas de alto standing.
El Pla del Real también tiene una proporción muy elevada de pisos caros respecto a su tamaño total.
-> Distritos con perfil más económico
Benicalap, La Saïdia, L’Olivereta, Rascanya tienen una mayoría significativa de pisos baratos yescasez de caros. Nos sugiere que son zonas más asequibles o donde predomina la vivienda de clase trabajadora/media.
Centro y zonas consolidadas (Ej: L’Eixample, Ciutat Vella, Pla del Real) -> Mayor concentración de viviendas caras.
Distritos periféricos o tradicionalmente más populares (Ej: Benicalap, La Saïdia, L’Olivereta) -> Predominan las viviendas baratas.
Zonas en transición o mixtas (Ej: Camins al Grau, Benimaclet, Patraix) -> Amplia gama de precios.
Ulteriormente, vamos a añadir en cada distrito las variables y sus medias, mínimos, máximos y desviaciones típicas, sobre cada rango de precio, y de esta forma no aplanar la base de datos.
Para ello solo vamos a tener en cuenta variables que compartamos con el dataframe de 2025, para poder usar el posterior modelo de predicción para este también.
Antes de empezar, crearemos la variable Precio_m2 que nos explica el precio por metro cuadrado de la vivienda.
Valencia_Sale$Precio_m2 <- round(Valencia_Sale$PRICE / Valencia_Sale$CONSTRUCTEDAREA, 2)
library(dplyr)
library(tidyr)
library(sf) # por si aún no estaba cargado
modelo_vars <- c(
"CONSTRUCTEDAREA","ROOMNUMBER","BATHNUMBER",
"DISTANCE_TO_CITY_CENTER","DISTANCE_TO_METRO",
"Precio_m2","RHabitacion_Banyo"
)
vars_bin <- c( "HASLIFT","BUILTTYPEID_1","BUILTTYPEID_2","BUILTTYPEID_3")
resumen <- Valencia_Sale %>%
st_drop_geometry() %>%
mutate(Precio_m2 = round(PRICE / CONSTRUCTEDAREA, 2)) %>%
group_by(DISTRITO, RANGO_PRECIO) %>%
summarise(
# Continuas: media, min, max, sd
across(
all_of(modelo_vars),
.fns = list(
media = \(x) mean(x, na.rm = TRUE),
min = \(x) min(x, na.rm = TRUE),
max = \(x) max(x, na.rm = TRUE),
sd = \(x) sd(x, na.rm = TRUE)
),
.names = "{.col}_{.fn}"
),
# Binarias: solo media (sin sd)
across(
all_of(vars_bin),
.fns = ~mean(.x, na.rm = TRUE),
.names = "{.col}_media"
),
.groups = "drop"
)
resumen_distritos <- resumen %>%
pivot_wider(
id_cols = DISTRITO,
names_from = RANGO_PRECIO,
values_from = -c(DISTRITO, RANGO_PRECIO),
names_glue = "{.value}_{RANGO_PRECIO}",
values_fill = NA
)
# 5) Lo convertimos a data.frame para verlo completo
resumen_distritos <- as.data.frame(resumen_distritos)
print(resumen_distritos)
## DISTRITO CONSTRUCTEDAREA_media_Barato CONSTRUCTEDAREA_media_Medio
## 1 Algirós 72.57222 104.61994
## 2 Benicalap 78.01170 108.21123
## 3 Benimaclet 76.91304 101.31809
## 4 Camins al Grau 73.07500 106.88125
## 5 Campanar 79.01000 107.30743
## 6 Ciutat Vella 66.84000 96.32913
## 7 El Pla del Real 61.61111 102.21268
## 8 Extramurs 65.47423 109.25310
## 9 Jesús 84.47425 106.15198
## 10 L'Eixample 65.26087 99.08920
## 11 L'Olivereta 78.78462 108.10646
## 12 La Saïdia 73.67452 103.90147
## 13 Patraix 84.13869 109.41815
## 14 Poblats Marítims 75.15730 96.88009
## 15 Quatre Carreres 85.43164 102.76020
## 16 Rascanya 80.29974 109.91770
## CONSTRUCTEDAREA_media_Caro CONSTRUCTEDAREA_min_Barato
## 1 157.6538 40
## 2 165.3182 38
## 3 189.1538 45
## 4 151.1628 53
## 5 157.4657 55
## 6 183.4884 26
## 7 190.0792 45
## 8 172.6821 28
## 9 178.6000 53
## 10 178.3452 24
## 11 154.6111 42
## 12 182.2375 30
## 13 199.1316 30
## 14 162.3636 30
## 15 169.5985 43
## 16 150.5227 46
## CONSTRUCTEDAREA_min_Medio CONSTRUCTEDAREA_min_Caro
## 1 42 90
## 2 45 100
## 3 39 103
## 4 40 95
## 5 45 89
## 6 29 55
## 7 38 84
## 8 37 76
## 9 60 121
## 10 32 58
## 11 50 90
## 12 47 90
## 13 45 60
## 14 38 100
## 15 41 105
## 16 43 82
## CONSTRUCTEDAREA_max_Barato CONSTRUCTEDAREA_max_Medio
## 1 113 219
## 2 153 260
## 3 135 252
## 4 87 245
## 5 134 187
## 6 126 260
## 7 110 181
## 8 148 220
## 9 147 182
## 10 121 200
## 11 140 240
## 12 150 216
## 13 135 265
## 14 150 270
## 15 140 314
## 16 142 229
## CONSTRUCTEDAREA_max_Caro CONSTRUCTEDAREA_sd_Barato CONSTRUCTEDAREA_sd_Medio
## 1 244 13.581548 23.31670
## 2 326 16.417181 25.76218
## 3 269 16.696018 23.64795
## 4 440 8.364723 27.86102
## 5 399 13.923670 26.16005
## 6 888 23.787632 34.78089
## 7 430 18.327539 23.97291
## 8 910 21.841805 29.69539
## 9 285 15.185462 20.80897
## 10 900 28.491175 27.73793
## 11 319 16.454259 23.43068
## 12 480 13.975887 24.79045
## 13 658 16.345694 23.17147
## 14 416 14.486512 24.92668
## 15 418 15.035942 23.03667
## 16 284 16.394426 26.97381
## CONSTRUCTEDAREA_sd_Caro ROOMNUMBER_media_Barato ROOMNUMBER_media_Medio
## 1 39.11720 2.638889 3.184971
## 2 51.17456 2.771277 2.996337
## 3 57.80009 2.855072 3.226611
## 4 45.93419 2.900000 2.925000
## 5 47.23549 2.900000 2.873921
## 6 74.48300 2.160000 2.467989
## 7 64.44734 1.611111 2.950920
## 8 65.71310 2.154639 3.167552
## 9 78.25152 2.918455 2.869301
## 10 69.87158 2.217391 2.953419
## 11 49.66729 2.737278 3.131938
## 12 85.15143 2.646597 3.075506
## 13 129.97238 2.939173 3.138742
## 14 58.74945 2.657303 2.876131
## 15 57.37294 2.920123 2.943544
## 16 47.45112 2.896684 3.050754
## ROOMNUMBER_media_Caro ROOMNUMBER_min_Barato ROOMNUMBER_min_Medio
## 1 3.730769 0 1
## 2 3.560606 0 0
## 3 3.784615 1 0
## 4 3.356589 1 0
## 5 3.368231 1 1
## 6 3.898947 0 0
## 7 3.989583 0 0
## 8 4.062500 0 0
## 9 4.000000 1 0
## 10 3.928783 0 0
## 11 3.500000 0 1
## 12 3.787500 0 0
## 13 3.000000 0 0
## 14 3.597403 0 0
## 15 3.532847 0 0
## 16 3.636364 0 0
## ROOMNUMBER_min_Caro ROOMNUMBER_max_Barato ROOMNUMBER_max_Medio
## 1 2 4 7
## 2 2 5 6
## 3 3 4 5
## 4 2 5 6
## 5 2 4 6
## 6 0 4 6
## 7 1 3 5
## 8 0 5 7
## 9 3 4 5
## 10 0 4 7
## 11 2 7 7
## 12 2 5 6
## 13 0 5 7
## 14 1 6 6
## 15 1 7 5
## 16 2 5 6
## ROOMNUMBER_max_Caro ROOMNUMBER_sd_Barato ROOMNUMBER_sd_Medio
## 1 7 0.7822321 0.8179637
## 2 5 0.7178127 0.8117332
## 3 6 0.6248615 0.7614397
## 4 6 0.5905235 0.8996690
## 5 5 0.5222330 0.8703062
## 6 11 0.9971388 1.2365207
## 7 10 0.9785276 0.9395915
## 8 10 1.0833994 1.1124537
## 9 5 0.6202693 0.6838288
## 10 15 1.1263990 1.0516478
## 11 7 0.7861929 0.8141894
## 12 7 0.6841127 0.8379306
## 13 5 0.7811409 0.7812966
## 14 10 0.7663085 0.8171453
## 15 7 0.7166658 0.8452056
## 16 7 0.7224120 0.8589558
## ROOMNUMBER_sd_Caro BATHNUMBER_media_Barato BATHNUMBER_media_Medio
## 1 1.0414487 1.027778 1.611272
## 2 0.6355806 1.131915 1.768010
## 3 0.6957978 1.057971 1.546778
## 4 0.6458301 1.025000 1.693750
## 5 0.6382734 1.090000 1.754750
## 6 1.5080741 1.140000 1.447250
## 7 1.0368451 1.055556 1.631902
## 8 1.2717455 1.030928 1.628909
## 9 1.0000000 1.124464 1.686930
## 10 1.3211428 1.173913 1.499504
## 11 1.2485285 1.085207 1.640582
## 12 1.0872535 1.058464 1.603131
## 13 1.0654272 1.113139 1.723956
## 14 1.1949426 1.051498 1.472285
## 15 0.7281230 1.107527 1.629961
## 16 1.0303645 1.089286 1.717421
## BATHNUMBER_media_Caro BATHNUMBER_min_Barato BATHNUMBER_min_Medio
## 1 2.153846 1 1
## 2 2.272727 1 1
## 3 2.984615 1 1
## 4 2.232558 0 1
## 5 2.155235 1 1
## 6 2.297895 1 1
## 7 2.472917 1 1
## 8 2.298913 0 0
## 9 2.800000 1 1
## 10 2.334322 1 1
## 11 2.444444 1 1
## 12 2.425000 0 1
## 13 1.973684 0 1
## 14 2.142857 0 1
## 15 2.262774 1 1
## 16 2.204545 1 1
## BATHNUMBER_min_Caro BATHNUMBER_max_Barato BATHNUMBER_max_Medio
## 1 2 4 4
## 2 1 2 3
## 3 2 2 4
## 4 1 3 3
## 5 1 2 3
## 6 0 3 3
## 7 1 2 4
## 8 1 2 4
## 9 2 2 3
## 10 1 2 3
## 11 1 4 4
## 12 1 2 3
## 13 1 4 4
## 14 1 3 4
## 15 2 3 3
## 16 1 2 3
## BATHNUMBER_max_Caro BATHNUMBER_sd_Barato BATHNUMBER_sd_Medio
## 1 4 0.2463262 0.5194231
## 2 3 0.3385784 0.4715913
## 3 4 0.2354007 0.5461942
## 4 5 0.3571612 0.4880628
## 5 5 0.2876235 0.4835967
## 6 10 0.4045658 0.5375470
## 7 6 0.2357023 0.5427283
## 8 10 0.2260903 0.5397885
## 9 4 0.3304644 0.4773970
## 10 5 0.3875534 0.5081184
## 11 4 0.2918017 0.5041088
## 12 6 0.2384134 0.4932254
## 13 3 0.3319710 0.4712047
## 14 10 0.2334847 0.5280164
## 15 4 0.3149435 0.5143544
## 16 4 0.2853377 0.4941815
## BATHNUMBER_sd_Caro DISTANCE_TO_CITY_CENTER_media_Barato
## 1 0.4640955 2.3041610
## 2 0.4818380 2.9139875
## 3 0.9098816 2.3687664
## 4 0.5220675 2.1704476
## 5 0.4596979 2.0509363
## 6 0.8394236 0.6821051
## 7 0.7530701 1.9006001
## 8 0.7254043 1.0731393
## 9 1.0954451 2.9293887
## 10 0.6741324 1.0236263
## 11 0.7047922 2.2542852
## 12 0.8233153 2.4837423
## 13 0.4341405 2.0794717
## 14 1.0093547 3.6844583
## 15 0.5039560 2.1518857
## 16 0.5286959 2.7375609
## DISTANCE_TO_CITY_CENTER_media_Medio DISTANCE_TO_CITY_CENTER_media_Caro
## 1 2.5388707 2.4025051
## 2 2.8697991 3.1276901
## 3 2.2858036 2.3530335
## 4 2.3555736 2.6297362
## 5 2.4499658 2.7506121
## 6 0.6659933 0.4425755
## 7 1.7269133 1.6121323
## 8 1.0068172 0.8405238
## 9 2.9587971 2.5916649
## 10 1.0274873 0.8481733
## 11 2.1544269 1.8387429
## 12 1.9414399 1.6164534
## 13 1.9869010 1.6963870
## 14 3.5698690 3.7050852
## 15 2.0769227 2.3060579
## 16 2.5177585 2.6278325
## DISTANCE_TO_CITY_CENTER_min_Barato DISTANCE_TO_CITY_CENTER_min_Medio
## 1 1.81284328 1.78133087
## 2 2.28328185 2.26389224
## 3 2.11786700 1.96293137
## 4 1.75264309 1.72299188
## 5 1.50011007 1.46390039
## 6 0.02096525 0.00305319
## 7 1.70288329 1.14939470
## 8 0.39948561 0.26186273
## 9 1.76089219 1.75784351
## 10 0.59561841 0.30793406
## 11 1.22740260 1.21571026
## 12 1.18135985 1.24862185
## 13 1.17208182 1.16392184
## 14 2.27056309 2.23579320
## 15 1.31976970 1.29799050
## 16 1.89864469 1.84908574
## DISTANCE_TO_CITY_CENTER_min_Caro DISTANCE_TO_CITY_CENTER_max_Barato
## 1 1.84903102 3.484003
## 2 2.37910746 3.839378
## 3 1.98719094 2.753317
## 4 1.71259334 2.726650
## 5 1.59385429 4.526430
## 6 0.01661463 1.236927
## 7 1.02648286 2.024245
## 8 0.26524430 1.666490
## 9 1.74721309 3.667146
## 10 0.30463512 1.569929
## 11 1.35819451 3.404196
## 12 1.16857217 3.781026
## 13 1.19148384 3.481656
## 14 2.36937234 4.734084
## 15 1.31000489 4.403703
## 16 2.00930759 3.838826
## DISTANCE_TO_CITY_CENTER_max_Medio DISTANCE_TO_CITY_CENTER_max_Caro
## 1 3.800319 3.320961
## 2 3.846088 3.716443
## 3 3.057712 2.696031
## 4 3.435174 3.386932
## 5 4.600284 3.717410
## 6 1.340555 1.174325
## 7 2.197583 2.188167
## 8 1.716731 1.634599
## 9 3.626211 2.834346
## 10 1.622172 1.477395
## 11 3.411979 2.227236
## 12 3.216132 2.724082
## 13 3.474190 2.880028
## 14 5.666819 4.690281
## 15 4.319968 3.838828
## 16 3.973272 3.142429
## DISTANCE_TO_CITY_CENTER_sd_Barato DISTANCE_TO_CITY_CENTER_sd_Medio
## 1 0.44649031 0.4623976
## 2 0.44524019 0.3458849
## 3 0.15724581 0.2320679
## 4 0.32364859 0.4085209
## 5 0.57740057 0.5388954
## 6 0.31101207 0.2827411
## 7 0.09677494 0.2356042
## 8 0.24950929 0.2886919
## 9 0.47694199 0.5343977
## 10 0.24498438 0.2322384
## 11 0.44151461 0.5330772
## 12 0.43536436 0.3787013
## 13 0.48570600 0.5332991
## 14 0.61412775 0.5990532
## 15 0.68996068 0.5994544
## 16 0.29256697 0.3400695
## DISTANCE_TO_CITY_CENTER_sd_Caro DISTANCE_TO_METRO_media_Barato
## 1 0.4670452 0.3122704
## 2 0.3250105 0.7640177
## 3 0.1886479 0.3781321
## 4 0.4597339 0.7419162
## 5 0.4440525 0.5734995
## 6 0.2489806 0.5853067
## 7 0.2749008 0.3080901
## 8 0.2976644 0.4101866
## 9 0.4726965 1.1993566
## 10 0.2988743 0.3603933
## 11 0.3048574 0.4086758
## 12 0.3669140 1.0402891
## 13 0.4033430 0.4552237
## 14 0.5036484 0.9915815
## 15 0.4120145 0.6502005
## 16 0.2918855 1.4102118
## DISTANCE_TO_METRO_media_Medio DISTANCE_TO_METRO_media_Caro
## 1 0.3954858 0.4715034
## 2 0.9031368 0.6150947
## 3 0.3683562 0.5305830
## 4 0.7772304 0.9829621
## 5 0.5401711 0.5456014
## 6 0.6180889 0.3829372
## 7 0.3504896 0.3152947
## 8 0.3395615 0.2578855
## 9 1.2014398 1.0212664
## 10 0.3660909 0.3208334
## 11 0.4174306 0.4574446
## 12 0.9966556 0.8656616
## 13 0.4598807 0.3875634
## 14 0.7911778 0.7775090
## 15 0.6604634 0.8325411
## 16 1.1232336 0.5028227
## DISTANCE_TO_METRO_min_Barato DISTANCE_TO_METRO_min_Medio
## 1 0.07533122 0.045949860
## 2 0.16230203 0.006064074
## 3 0.09557769 0.007133824
## 4 0.53111053 0.463635446
## 5 0.19139264 0.056673040
## 6 0.24426369 0.063158733
## 7 0.14818785 0.011560362
## 8 0.04968361 0.007292860
## 9 0.37891218 0.092605394
## 10 0.10920794 0.016856970
## 11 0.07376401 0.013630444
## 12 0.19315961 0.119899738
## 13 0.01784304 0.003744207
## 14 0.06769648 0.037709383
## 15 0.02777819 0.015978590
## 16 0.27962104 0.039397715
## DISTANCE_TO_METRO_min_Caro DISTANCE_TO_METRO_max_Barato
## 1 0.146596435 0.7690961
## 2 0.004027793 1.6915917
## 3 0.084821356 0.7938225
## 4 0.505636277 0.9549927
## 5 0.046448634 1.0437969
## 6 0.007839640 1.0995868
## 7 0.023617802 0.6823616
## 8 0.011604426 0.6181701
## 9 0.454792944 1.7441955
## 10 0.034167968 0.6139251
## 11 0.295115228 0.8557135
## 12 0.152151556 1.5471756
## 13 0.071259563 1.3097971
## 14 0.084174069 2.3706684
## 15 0.142519633 2.1579629
## 16 0.103996758 1.8659599
## DISTANCE_TO_METRO_max_Medio DISTANCE_TO_METRO_max_Caro
## 1 1.2857529 1.0769789
## 2 1.7523872 1.5258473
## 3 0.8450519 0.7794672
## 4 1.2214592 1.2908501
## 5 1.1231967 1.1140300
## 6 1.1814836 1.1358889
## 7 0.8446743 0.8136927
## 8 0.6573257 0.6458822
## 9 1.7381787 1.2173759
## 10 0.6713721 0.7077870
## 11 0.8161971 0.6631094
## 12 1.5545200 1.4309608
## 13 1.2924310 0.7029136
## 14 2.8591845 2.2311958
## 15 2.0149215 1.7021423
## 16 1.8822322 1.7157433
## DISTANCE_TO_METRO_sd_Barato DISTANCE_TO_METRO_sd_Medio
## 1 0.1131955 0.1869619
## 2 0.2583819 0.4318054
## 3 0.1387193 0.1706041
## 4 0.1271462 0.1814880
## 5 0.1736973 0.2231835
## 6 0.2592810 0.2508801
## 7 0.1102186 0.1657391
## 8 0.1484049 0.1543184
## 9 0.3728838 0.3800455
## 10 0.1270713 0.1284014
## 11 0.1529942 0.1621113
## 12 0.2526080 0.3012703
## 13 0.2099230 0.2048173
## 14 0.6130926 0.5124479
## 15 0.3751785 0.3354662
## 16 0.2471987 0.4499716
## DISTANCE_TO_METRO_sd_Caro Precio_m2_media_Barato Precio_m2_media_Medio
## 1 0.2134544 1087.8235 1684.836
## 2 0.4886584 872.4689 1636.177
## 3 0.1689243 1135.3214 1823.081
## 4 0.1564671 1164.3428 1924.573
## 5 0.2647520 1005.3839 1849.507
## 6 0.2220629 1366.3000 2333.006
## 7 0.1237661 1561.1883 2114.023
## 8 0.1532761 1380.4793 1854.202
## 9 0.3182450 885.9669 1299.312
## 10 0.1414985 1408.1591 2216.507
## 11 0.1221761 908.3278 1415.650
## 12 0.3041816 905.3542 1537.641
## 13 0.1742511 963.0324 1436.949
## 14 0.4747681 1037.4520 1649.651
## 15 0.2609566 920.5623 1633.480
## 16 0.3645880 904.5420 1584.119
## Precio_m2_media_Caro Precio_m2_min_Barato Precio_m2_min_Medio
## 1 2485.241 527.78 653.63
## 2 2930.642 483.87 480.69
## 3 2176.290 525.93 908.63
## 4 3080.370 810.13 977.10
## 5 2662.303 520.00 855.61
## 6 3051.864 523.81 680.77
## 7 2895.420 663.64 802.26
## 8 2411.434 547.30 754.84
## 9 2384.488 485.15 704.40
## 10 3314.943 522.39 753.33
## 11 2585.467 487.50 635.00
## 12 2685.557 480.77 664.74
## 13 2516.939 481.82 650.00
## 14 2481.179 485.71 604.76
## 15 2651.159 492.06 761.63
## 16 2668.107 481.93 554.59
## Precio_m2_min_Caro Precio_m2_max_Barato Precio_m2_max_Medio
## 1 1302.90 2255.81 3547.62
## 2 1244.00 2184.21 3706.90
## 3 1301.12 1777.78 3690.48
## 4 1557.14 1679.25 4600.00
## 5 1030.22 1596.77 3721.52
## 6 1191.92 3000.00 4777.78
## 7 1338.46 2044.44 3947.37
## 8 814.29 2733.33 4320.00
## 9 1887.72 1492.31 2462.69
## 10 1414.44 2583.33 4408.16
## 11 1700.93 2152.17 4800.00
## 12 800.00 2966.67 3472.22
## 13 938.52 2333.33 3923.08
## 14 1082.93 3266.67 4072.46
## 15 1282.05 2255.81 3615.38
## 16 1148.41 1923.08 3373.33
## Precio_m2_max_Caro Precio_m2_sd_Barato Precio_m2_sd_Medio Precio_m2_sd_Caro
## 1 4088.89 327.4735 390.9572 634.2809
## 2 5688.00 244.6925 495.9796 1026.4763
## 3 3750.00 269.8564 525.1413 506.8781
## 4 6744.08 159.2921 525.7616 781.7358
## 5 5504.00 207.1331 535.9392 633.5551
## 6 7487.50 566.1873 727.4396 951.0296
## 7 8010.70 415.7852 506.7618 859.2890
## 8 6770.73 425.1636 472.0630 685.0255
## 9 2634.92 191.1962 282.7287 292.7687
## 10 9421.82 644.0920 562.7593 1152.4918
## 11 4355.56 220.6350 330.2420 687.9745
## 12 5095.74 260.4320 374.5018 848.1209
## 13 9250.00 230.6748 370.9646 1635.1719
## 14 7036.50 271.3271 420.4556 805.3820
## 15 5029.59 220.2394 465.1487 653.9403
## 16 4817.07 243.1660 519.0878 642.5383
## RHabitacion_Banyo_media_Barato RHabitacion_Banyo_media_Medio
## 1 0.4259259 0.5261457
## 2 0.4267553 0.6176231
## 3 0.3925121 0.4994109
## 4 0.3695833 0.6124479
## 5 0.3883333 0.6547784
## 6 0.6033333 0.6412534
## 7 0.7222222 0.5904567
## 8 0.5587629 0.5512038
## 9 0.4021817 0.6105876
## 10 0.5942029 0.5507976
## 11 0.4374810 0.5458729
## 12 0.4214223 0.5478514
## 13 0.4052920 0.5635313
## 14 0.4304463 0.5471814
## 15 0.4029113 0.5867990
## 16 0.4018282 0.5915181
## RHabitacion_Banyo_media_Caro RHabitacion_Banyo_min_Barato
## 1 0.6109890 0.00
## 2 0.6494949 0.00
## 3 0.7900000 0.25
## 4 0.6766150 0.00
## 5 0.6502407 0.25
## 6 0.6628470 0.00
## 7 0.6359821 0.00
## 8 0.5877588 0.00
## 9 0.6866667 0.25
## 10 0.6396802 0.00
## 11 0.7271164 0.00
## 12 0.6588988 0.00
## 13 0.6728070 0.00
## 14 0.6106679 0.00
## 15 0.6716719 0.00
## 16 0.6271104 0.00
## RHabitacion_Banyo_min_Medio RHabitacion_Banyo_min_Caro
## 1 0.1428571 0.2857143
## 2 0.0000000 0.5000000
## 3 0.0000000 0.3333333
## 4 0.0000000 0.2000000
## 5 0.2500000 0.3333333
## 6 0.0000000 0.0000000
## 7 0.0000000 0.2000000
## 8 0.0000000 0.0000000
## 9 0.0000000 0.5000000
## 10 0.0000000 0.0000000
## 11 0.2000000 0.5000000
## 12 0.0000000 0.3333333
## 13 0.0000000 0.0000000
## 14 0.0000000 0.3333333
## 15 0.0000000 0.2857143
## 16 0.0000000 0.3333333
## RHabitacion_Banyo_max_Barato RHabitacion_Banyo_max_Medio
## 1 1.333333 1
## 2 2.000000 1
## 3 1.000000 1
## 4 1.000000 2
## 5 1.000000 2
## 6 1.500000 2
## 7 1.000000 2
## 8 1.000000 2
## 9 1.000000 1
## 10 1.000000 2
## 11 1.000000 2
## 12 2.000000 1
## 13 2.000000 2
## 14 2.000000 2
## 15 1.000000 2
## 16 2.000000 2
## RHabitacion_Banyo_max_Caro RHabitacion_Banyo_sd_Barato
## 1 1.000000 0.2042930
## 2 1.500000 0.1899799
## 3 1.000000 0.1415523
## 4 1.333333 0.1461709
## 5 1.000000 0.1214969
## 6 2.000000 0.3097801
## 7 1.666667 0.3429972
## 8 1.500000 0.3050889
## 9 0.800000 0.1447468
## 10 1.500000 0.3161323
## 11 1.000000 0.2083533
## 12 1.333333 0.1551523
## 13 1.000000 0.1894462
## 14 1.000000 0.2033056
## 15 2.000000 0.1583179
## 16 1.333333 0.1861938
## RHabitacion_Banyo_sd_Medio RHabitacion_Banyo_sd_Caro HASLIFT_media_Barato
## 1 0.1835395 0.1738546 0.4388889
## 2 0.1977772 0.1513746 0.3957447
## 3 0.1986214 0.1963380 0.1884058
## 4 0.2260748 0.1435306 0.8000000
## 5 0.2249038 0.1269690 0.3800000
## 6 0.3166827 0.3269646 0.2000000
## 7 0.2894153 0.1656145 0.8333333
## 8 0.2350645 0.1816535 0.5154639
## 9 0.2137749 0.1238278 0.5793991
## 10 0.2612655 0.2277123 0.2608696
## 11 0.1947816 0.1732458 0.6331361
## 12 0.2077086 0.1830906 0.5017452
## 13 0.1831023 0.2276140 0.6253041
## 14 0.2420770 0.1504427 0.3099251
## 15 0.2417475 0.2266916 0.4961598
## 16 0.2439345 0.1536959 0.5063776
## HASLIFT_media_Medio HASLIFT_media_Caro BUILTTYPEID_1_media_Barato
## 1 0.9205202 0.8846154 0.005555556
## 2 0.9597070 0.9848485 0.004255319
## 3 0.8253638 0.9538462 0.000000000
## 4 0.9406250 0.9883721 0.000000000
## 5 0.9291883 0.9747292 0.000000000
## 6 0.6961226 0.9263158 0.000000000
## 7 0.9325153 0.9729167 0.000000000
## 8 0.8932153 0.9782609 0.000000000
## 9 0.9452888 1.0000000 0.000000000
## 10 0.8325074 0.9525223 0.000000000
## 11 0.9599636 1.0000000 0.000000000
## 12 0.9355433 0.9625000 0.000000000
## 13 0.9596735 0.8947368 0.006082725
## 14 0.7047511 0.8051948 0.001872659
## 15 0.9424259 0.9781022 0.000000000
## 16 0.9588477 1.0000000 0.001275510
## BUILTTYPEID_1_media_Medio BUILTTYPEID_1_media_Caro
## 1 0.007225434 0.038461538
## 2 0.122100122 0.106060606
## 3 0.004158004 0.000000000
## 4 0.006250000 0.023255814
## 5 0.063903282 0.108303249
## 6 0.004508566 0.000000000
## 7 0.049079755 0.022916667
## 8 0.002949853 0.038043478
## 9 0.009118541 0.000000000
## 10 0.000000000 0.001978239
## 11 0.034576888 0.388888889
## 12 0.055248619 0.287500000
## 13 0.060489678 0.131578947
## 14 0.027149321 0.090909091
## 15 0.119060928 0.386861314
## 16 0.050754458 0.022727273
## BUILTTYPEID_2_media_Barato BUILTTYPEID_2_media_Medio
## 1 0.2000000 0.06791908
## 2 0.1702128 0.03052503
## 3 0.3623188 0.06652807
## 4 0.3000000 0.05625000
## 5 0.2100000 0.06390328
## 6 0.2000000 0.15329125
## 7 0.1666667 0.17382413
## 8 0.3608247 0.18348083
## 9 0.1180258 0.04255319
## 10 0.3043478 0.24281467
## 11 0.1597633 0.07370337
## 12 0.1884817 0.09484346
## 13 0.2055961 0.05568891
## 14 0.2209738 0.08540724
## 15 0.1812596 0.06707658
## 16 0.1632653 0.05486968
## BUILTTYPEID_2_media_Caro BUILTTYPEID_3_media_Barato
## 1 0.038461538 0.7944444
## 2 0.000000000 0.8255319
## 3 0.000000000 0.6376812
## 4 0.003875969 0.7000000
## 5 0.021660650 0.7900000
## 6 0.222105263 0.8000000
## 7 0.089583333 0.8333333
## 8 0.108695652 0.6391753
## 9 0.000000000 0.8819742
## 10 0.229475767 0.6956522
## 11 0.000000000 0.8402367
## 12 0.012500000 0.8115183
## 13 0.052631579 0.7883212
## 14 0.012987013 0.7771536
## 15 0.014598540 0.8187404
## 16 0.000000000 0.8354592
## BUILTTYPEID_3_media_Medio BUILTTYPEID_3_media_Caro
## 1 0.9248555 0.9230769
## 2 0.8473748 0.8939394
## 3 0.9293139 1.0000000
## 4 0.9375000 0.9728682
## 5 0.8721934 0.8700361
## 6 0.8422002 0.7778947
## 7 0.7770961 0.8875000
## 8 0.8135693 0.8532609
## 9 0.9483283 1.0000000
## 10 0.7571853 0.7685460
## 11 0.8917197 0.6111111
## 12 0.8499079 0.7000000
## 13 0.8838214 0.8157895
## 14 0.8874434 0.8961039
## 15 0.8138625 0.5985401
## 16 0.8943759 0.9772727
Hemos creado un data frame paralelo en el que contamos con todos los distritos. Las columnas de este son la media de las variables seleccionadas (coincidentes con 2025), divididas en distintos rangos de precio. Además, sacaremos también los valores mínimos y máximos de cada variable, así como su desviación típica.
Por otra parte, de las variables que son binarias hemos decidido sacar solamente la media y desviación típica, así podremos apreciar la tendencia más habitual de los pisos en determinados distritos dependiendo de su rango de precio.
Esto se realiza para evitar aplanar la base de datos y juntar todos los tipos de pisos, así podemos conservar las diferencias y variabilidad entre ellos.
Por otra parte, nuestro siguiente paso será la realización del clustering, así conseguiremos fácilmente agrupar distritos con características similares.
library(dplyr)
library(tidyr)
library(cluster)
library(factoextra)
library(tibble)
# 1) Ponemos DISTRITO como rownames y quitamos la columna
datos_raw <- resumen_distritos %>%
column_to_rownames("DISTRITO")
# 2) Seleccionamos sólo las columnas numéricas
datos_num <- datos_raw %>% dplyr::select(where(is.numeric))
# 3) Estandarizamos
datos_Z <- scale(datos_num, center = TRUE, scale = TRUE)
datos_Z <- as.data.frame(datos_Z)
# 4) Distancias y heatmap
dist_mat <- dist(datos_Z, method = "euclidean")
factoextra::fviz_dist(dist_mat,
show_labels = TRUE,
lab_size = 3)
dist_mat_manh <- dist(datos_Z, method = "manhattan")
factoextra::fviz_dist(dist_mat_manh,
show_labels = TRUE,
lab_size = 3)
Gracias al mapa de distancias podemos intuir visualmente antes de
realizar algún método de clustering como se agruparán los distritos.
Varias “manchas” azul claro (distancia pequeña entre ellas) forman
bloques compactos. Cada bloque indica un conjunto de distritos con
perfiles muy parecidos en las variables medias que empleamos. Entre esos
bloques predominan valores cálidos (> 10 – 12), prueba de que esos
grupos están bien separados: distritos del bloque A son bastante
distintos de los del bloque B.
Existe una estructura de agrupamiento clara: los bloques azulados sugieren 3-4 clusters de distritos con características inmobiliarias semejantes.
set.seed(100)
n_obs <- nrow(datos_Z) # 16
m_vec <- c(5, 8, 10, 12) # tamaños de muestra viables
seeds <- sample(1:1000, 10) # 10 semillas
hop_val <- numeric()
for (m in m_vec) {
for (s in seeds) {
h <- get_clust_tendency(data = datos_Z,
n = m,
seed = s,
graph = FALSE)$hopkins_stat
hop_val <- c(hop_val, as.numeric(h))
}
}
summary(hop_val)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.5464 0.5629 0.5733 0.5768 0.5892 0.6225
Observamos el valor del estadístico de Hopkins que supera por poco el 0,5 , y su valor maáximo llega a los 0,6395. Esto indica una débil o moderada tendencia al agrupamiento.
No es un valor extremadamente alto con el que podamos afirmar de manera segura que se forman clústers muy bien definidos.
No obstante, nos parece suficiente, y seguiremos con el clustering.
library(grid)
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.4.3
##
## Adjuntando el paquete: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
p1 = fviz_nbclust(x = datos_Z, FUNcluster = hcut, method = "silhouette",
hc_method = "ward.D2", k.max = 10, verbose = FALSE,
hc_metric = "euclidean") + labs(title = "Num. optimo clusters")
p2 = fviz_nbclust(x = datos_Z, FUNcluster = hcut, method = "wss",
hc_method = "ward.D2", k.max = 10, verbose = FALSE,
hc_metric = "euclidean") + labs(title = "Num. optimo clusters")
grid.arrange(p1, p2, nrow = 1)
dist_mat <- dist(datos_Z, method = "euclidean")
clust1 <- hclust(dist_mat, method="ward.D2")
grupos1 <- cutree(clust1, k=5)
table(grupos1)
## grupos1
## 1 2 3 4 5
## 4 5 2 1 4
fviz_dend(clust1, k = 5,
cex = 0.5, color_labels_by_k = TRUE,
rect = TRUE) # dibujar rectángulos
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the factoextra package.
## Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
p1 = fviz_nbclust(x = datos_Z, FUNcluster = kmeans, method = "silhouette",
k.max = 10, verbose = FALSE) +
labs(title = "K-means")
p2 = fviz_nbclust(x = datos_Z, FUNcluster = kmeans, method = "wss",
k.max = 10, verbose = FALSE) +
labs(title = "K-means")
grid.arrange(p1, p2, nrow = 1)
A la vista de todos los métodos que estamos empleando, el número más razonable de clusters sería 5 o 6.
library(NbClust)
res.km <- NbClust(data = datos_Z, distance = "euclidean",
min.nc = 2, max.nc = 8, method = "kmeans",
index = "silhouette")
res.km$All.index # todos los valores de índice para k = 2,…,8
## 2 3 4 5 6 7 8
## 0.2656 0.1341 0.1368 0.1379 0.1883 0.3192 0.4396
res.km$Best.nc
## Number_clusters Value_Index
## 8.0000 0.4396
set.seed(112)
clust3 <- kmeans(datos_Z, centers = 5, nstart = 20)
table(clust3$cluster)
##
## 1 2 3 4 5
## 2 3 4 5 2
p1 = fviz_nbclust(x = datos_Z, FUNcluster = pam, method = "silhouette",
k.max = 10, verbose = FALSE) +
labs(title = "Numero optimo de clusters")
p2 = fviz_nbclust(x = datos_Z, FUNcluster = pam, method = "wss",
k.max = 10, verbose = FALSE) +
labs(title = "Numero optimo de clusters")
grid.arrange(p1, p2, nrow = 1)
Como en el resto de gráficas, con 2 clusters conseguimos el ‘peak’ del coeficiente de silhouette, no obstante hay bastante variabilidad intracluster. Nos conviene más aumentar el número de cluster y ganar unos clusters con menos variabilidad.
Desde 3 hasta 8 clusters el coef. es relativamente plano, decidiremos quedarnos por ejemplo con 5 clusters.
clust4 <- pam(datos_Z, k =5)
table(clust4$clustering)
##
## 1 2 3 4 5
## 4 6 1 4 1
Decidiremos que tipo de clustering realizar, pero sobre los datos sin PCA
Vamos a comprobar que método de clustering agrupa de la mejor manera nuestros distritos y es el que usaremos finalmente:
library(ggsci)
## Warning: package 'ggsci' was built under R version 4.4.3
# ward
dist_mat <- dist(datos_Z, method = "euclidean")
clust1 <- hclust(dist_mat, method="ward.D2")
grupos1 <- cutree(clust1, k=5)
# k-medias
set.seed(114)
clust3 <- kmeans(datos_Z, centers = 5, nstart = 20)
# k-medoides
clust4 <- pam(datos_Z, k =5)
colores = pal_npg("nrc")(6)
colores2 = pal_npg("nrc")(7)
par(mfrow = c(1,3))
plot(silhouette(grupos1, dist_mat), col=colores, border=NA, main = "WARD")
plot(silhouette(clust3$cluster, dist_mat), col=colores, border=NA, main = "K-MEDIAS")
plot(silhouette(clust4$clustering, dist_mat), col=colores2, border=NA, main = "K-MEDOIDES")
metodos = c("kmeans","pam")
validacion = suppressMessages(clValid(datos_Z, nClust = 2:5, metric = "euclidean",
clMethods = metodos,
validation = c("internal", "stability"),
method = "ward"))
summary(validacion)
##
## Clustering Methods:
## kmeans pam
##
## Cluster sizes:
## 2 3 4 5
##
## Validation Measures:
## 2 3 4 5
##
## kmeans APN 0.0000 0.0182 0.0298 0.0049
## AD 10.3073 9.2705 8.3876 7.4043
## ADM 0.0000 0.2041 0.4129 0.0925
## FOM 0.8406 0.8099 0.8123 0.7691
## Connectivity 4.9837 18.0560 22.5849 25.1833
## Dunn 0.7764 0.6234 0.6442 0.7166
## Silhouette 0.2656 0.1341 0.1286 0.1379
## pam APN 0.0000 0.0000 0.0045 0.0039
## AD 10.3073 9.2960 8.3948 7.4845
## ADM 0.0000 0.0000 0.0848 0.0937
## FOM 0.8406 0.8148 0.8092 0.7730
## Connectivity 4.9837 16.4798 19.2155 22.1806
## Dunn 0.7764 0.6178 0.6535 0.6564
## Silhouette 0.2656 0.1234 0.1289 0.1276
##
## Optimal Scores:
##
## Score Method Clusters
## APN 0.0000 kmeans 2
## AD 7.4043 kmeans 5
## ADM 0.0000 kmeans 2
## FOM 0.7691 kmeans 5
## Connectivity 4.9837 kmeans 2
## Dunn 0.7764 kmeans 2
## Silhouette 0.2656 kmeans 2
Elegimos el método de las k-means, empleando 5 clusters.
Pese a no ser el número de clústers recomendado por silhouette, en global suele tener en casi todos los métodos un pico en este estadístico, además de bajar significativamente la variabilidad intracluster en comparación con solamente 2 clústers.
Por ello, decidiremos usar el método de k-means con 5 clústers:
library(dplyr) # lo ponemos arriba para que use las instrucciones de esta librería
distr_cluster <- data.frame(
DISTRITO = rownames(datos_Z),
CLUSTER = clust3$cluster
)
# 2. Mostrar lista de distritos agrupados por cluster
clusters_lista <- split(distr_cluster$DISTRITO, distr_cluster$CLUSTER)
# 3. Imprimir de forma legible
for (i in sort(unique(distr_cluster$CLUSTER))) {
cat(paste0("\n📦 Cluster ", i, ":\n"))
print(clusters_lista[[as.character(i)]])
}
##
## 📦 Cluster 1:
## [1] "Benimaclet" "Jesús"
##
## 📦 Cluster 2:
## [1] "Camins al Grau" "Campanar"
##
## 📦 Cluster 3:
## [1] "Ciutat Vella" "El Pla del Real" "Extramurs" "L'Eixample"
##
## 📦 Cluster 4:
## [1] "Algirós" "L'Olivereta" "Patraix"
##
## 📦 Cluster 5:
## [1] "Benicalap" "La Saïdia" "Poblats Marítims" "Quatre Carreres"
## [5] "Rascanya"
perfiles = aggregate(datos_Z, by = list("cluster" = clust3$cluster), mean)
kable(perfiles)
| cluster | CONSTRUCTEDAREA_media_Barato | CONSTRUCTEDAREA_media_Medio | CONSTRUCTEDAREA_media_Caro | CONSTRUCTEDAREA_min_Barato | CONSTRUCTEDAREA_min_Medio | CONSTRUCTEDAREA_min_Caro | CONSTRUCTEDAREA_max_Barato | CONSTRUCTEDAREA_max_Medio | CONSTRUCTEDAREA_max_Caro | CONSTRUCTEDAREA_sd_Barato | CONSTRUCTEDAREA_sd_Medio | CONSTRUCTEDAREA_sd_Caro | ROOMNUMBER_media_Barato | ROOMNUMBER_media_Medio | ROOMNUMBER_media_Caro | ROOMNUMBER_min_Barato | ROOMNUMBER_min_Medio | ROOMNUMBER_min_Caro | ROOMNUMBER_max_Barato | ROOMNUMBER_max_Medio | ROOMNUMBER_max_Caro | ROOMNUMBER_sd_Barato | ROOMNUMBER_sd_Medio | ROOMNUMBER_sd_Caro | BATHNUMBER_media_Barato | BATHNUMBER_media_Medio | BATHNUMBER_media_Caro | BATHNUMBER_min_Barato | BATHNUMBER_min_Medio | BATHNUMBER_min_Caro | BATHNUMBER_max_Barato | BATHNUMBER_max_Medio | BATHNUMBER_max_Caro | BATHNUMBER_sd_Barato | BATHNUMBER_sd_Medio | BATHNUMBER_sd_Caro | DISTANCE_TO_CITY_CENTER_media_Barato | DISTANCE_TO_CITY_CENTER_media_Medio | DISTANCE_TO_CITY_CENTER_media_Caro | DISTANCE_TO_CITY_CENTER_min_Barato | DISTANCE_TO_CITY_CENTER_min_Medio | DISTANCE_TO_CITY_CENTER_min_Caro | DISTANCE_TO_CITY_CENTER_max_Barato | DISTANCE_TO_CITY_CENTER_max_Medio | DISTANCE_TO_CITY_CENTER_max_Caro | DISTANCE_TO_CITY_CENTER_sd_Barato | DISTANCE_TO_CITY_CENTER_sd_Medio | DISTANCE_TO_CITY_CENTER_sd_Caro | DISTANCE_TO_METRO_media_Barato | DISTANCE_TO_METRO_media_Medio | DISTANCE_TO_METRO_media_Caro | DISTANCE_TO_METRO_min_Barato | DISTANCE_TO_METRO_min_Medio | DISTANCE_TO_METRO_min_Caro | DISTANCE_TO_METRO_max_Barato | DISTANCE_TO_METRO_max_Medio | DISTANCE_TO_METRO_max_Caro | DISTANCE_TO_METRO_sd_Barato | DISTANCE_TO_METRO_sd_Medio | DISTANCE_TO_METRO_sd_Caro | Precio_m2_media_Barato | Precio_m2_media_Medio | Precio_m2_media_Caro | Precio_m2_min_Barato | Precio_m2_min_Medio | Precio_m2_min_Caro | Precio_m2_max_Barato | Precio_m2_max_Medio | Precio_m2_max_Caro | Precio_m2_sd_Barato | Precio_m2_sd_Medio | Precio_m2_sd_Caro | RHabitacion_Banyo_media_Barato | RHabitacion_Banyo_media_Medio | RHabitacion_Banyo_media_Caro | RHabitacion_Banyo_min_Barato | RHabitacion_Banyo_min_Medio | RHabitacion_Banyo_min_Caro | RHabitacion_Banyo_max_Barato | RHabitacion_Banyo_max_Medio | RHabitacion_Banyo_max_Caro | RHabitacion_Banyo_sd_Barato | RHabitacion_Banyo_sd_Medio | RHabitacion_Banyo_sd_Caro | HASLIFT_media_Barato | HASLIFT_media_Medio | HASLIFT_media_Caro | BUILTTYPEID_1_media_Barato | BUILTTYPEID_1_media_Medio | BUILTTYPEID_1_media_Caro | BUILTTYPEID_2_media_Barato | BUILTTYPEID_2_media_Medio | BUILTTYPEID_2_media_Caro | BUILTTYPEID_3_media_Barato | BUILTTYPEID_3_media_Medio | BUILTTYPEID_3_media_Caro |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 0.7752863 | -0.1784387 | 0.8249515 | 0.9582184 | 1.0481004 | 1.3602758 | 0.4356245 | -0.4571546 | -0.8728670 | -0.1921122 | -1.0228049 | 0.1892533 | 0.6932645 | 0.3194527 | 0.7764785 | 1.677051 | -0.4651303 | 1.5158477 | -0.7328549 | -1.3764693 | -0.7817903 | -0.8954678 | -1.1451218 | -0.5948166 | 0.1370428 | -0.1200466 | 2.1921716 | 0.6527912 | 0.25 | 1.4938253 | -0.7752171 | 0.1219875 | -0.5936991 | -0.2350175 | 0.1662529 | 1.5218650 | 0.6205505 | 0.6440974 | 0.4373557 | 0.7613865 | 0.7424967 | 0.6609736 | 0.0129473 | 0.0090117 | -0.0926641 | -0.4627577 | -0.1920801 | -0.3129416 | 0.3747371 | 0.4846870 | 0.8048658 | 0.5182660 | -0.1133746 | 0.8729098 | 0.0203430 | -0.1141097 | -0.3775669 | 0.1943491 | 0.0851817 | -0.0292312 | -0.3769515 | -0.6465396 | -1.3593197 | -0.3102566 | 0.7082085 | 1.1515215 | -1.1953237 | -1.3787187 | -1.4302971 | -0.5473838 | -0.6086337 | -1.3223374 | -0.6346791 | -0.5213566 | 1.6227736 | 2.0155644 | -0.4516922 | 0.8847549 | -0.7851403 | -1.4361407 | -1.1167255 | -0.9074978 | -0.6046019 | -0.4586379 | -0.4998290 | -0.1232253 | 0.4428650 | -0.5571434 | -0.8100766 | -0.7718003 | 0.2837036 | -0.6624945 | -0.6640645 | -0.2688609 | 1.2708039 | 1.2047319 |
| 2 | 0.1368454 | 0.5828891 | -1.1298191 | 1.4496125 | 0.0779579 | 0.2554833 | -1.2650536 | -0.4844474 | -0.2574877 | -1.2261970 | 0.4152773 | -0.7941481 | 0.7276952 | -0.4926055 | -1.0820538 | 1.677051 | 0.7752171 | 0.5457052 | -0.2818673 | -0.0809688 | -0.7817903 | -1.2689324 | 0.0088512 | -1.3532623 | -0.6264590 | 0.9846625 | -0.5850349 | -0.3916747 | 0.25 | -0.3447289 | -0.1550434 | -0.8539126 | -0.1806910 | 0.4440739 | -0.8319971 | -0.9152635 | -0.0849734 | 0.3549179 | 0.6844662 | 0.2855665 | 0.3500126 | 0.3626814 | 0.3950663 | 0.5952897 | 0.7369283 | 0.3503686 | 0.4805771 | 0.9798024 | -0.0121850 | 0.0496262 | 0.7572260 | 1.4123676 | 1.7622324 | 0.9134498 | -0.4531769 | -0.3167943 | 0.0659151 | -0.5994107 | -0.5152192 | -0.3113177 | -0.0419972 | 0.4719791 | 0.6194696 | 1.5264569 | 1.5593800 | 0.1396020 | -1.1897005 | 0.4312576 | 0.0737355 | -0.8901510 | 0.5763644 | -0.3046439 | -0.8167435 | 1.3131261 | 0.0728089 | 0.7752171 | 1.0720887 | 0.0449875 | -0.7851403 | 0.6527912 | -0.3911374 | -1.0384885 | -0.0880927 | -0.9494374 | 0.5828759 | 0.4483005 | 0.5305847 | -0.5571434 | -0.0878505 | -0.2787466 | 0.4870348 | -0.5708092 | -0.4958673 | -0.4733154 | 0.6703149 | 0.5877685 |
| 3 | -1.4068328 | -0.6348779 | 0.6445543 | -0.8353699 | -1.1000723 | -1.0564579 | -0.3868346 | -0.5049170 | 1.3079509 | 1.3539446 | 1.0276236 | 0.2169079 | -1.5203252 | -0.5718461 | 1.0488090 | -0.559017 | -0.4651303 | -1.1520442 | -0.7328549 | 0.2429064 | 1.3625489 | 1.4958519 | 1.4308756 | 1.0136663 | 0.3381653 | -0.7882732 | 0.0397284 | 0.1305582 | -0.75 | -0.8043675 | -0.4651303 | 0.1219875 | 0.9550812 | 0.2906599 | 0.9447548 | 0.3091798 | -1.3178702 | -1.3522106 | -1.3057172 | -1.1534914 | -1.3597787 | -1.3798287 | -1.4426474 | -1.3988012 | -1.3013103 | -1.0205030 | -1.1096257 | -0.8522084 | -0.7259127 | -0.7782591 | -1.0637725 | -0.1984851 | -0.3377181 | -0.7557602 | -0.8850196 | -0.8836476 | -0.7527728 | -0.5178936 | -0.7414400 | -0.7429684 | 1.5112498 | 1.3040436 | 0.7771113 | 0.3661122 | 0.2532146 | -0.2100055 | 0.6163096 | 0.7694340 | 0.9965226 | 1.4976175 | 0.9162796 | 0.3708391 | 1.5661417 | 0.1420347 | -0.5864632 | -0.4651303 | -0.4516922 | -1.1680098 | -0.5159493 | 0.6527912 | 0.9693404 | 1.5581623 | 1.2537835 | 0.8339866 | -0.1398990 | -0.6619649 | 0.0747588 | -0.5571434 | -0.6196999 | -0.6538608 | 0.5276224 | 1.5536504 | 1.4760901 | -0.5141273 | -1.2267873 | -0.1949581 |
| 4 | 0.4739701 | 0.6479730 | -0.0618503 | -0.1883677 | 0.5168319 | -0.4073922 | -0.2149081 | 0.2069705 | -0.3114683 | -0.2956469 | -0.6986791 | 0.4136804 | 0.3941653 | 0.8877879 | -0.9142404 | -0.559017 | 1.1886662 | -0.1010565 | 0.4697788 | 1.2145318 | -0.4839654 | 0.0108577 | -0.5633566 | 0.4020979 | -0.2217041 | 0.3094017 | -0.5979112 | -0.0435194 | 0.25 | 0.2681225 | 1.7054776 | 1.0978876 | -0.7313685 | -0.1128210 | -0.3546755 | -0.7083045 | 0.0486229 | 0.1230313 | -0.1220818 | -0.0523192 | 0.0464564 | 0.1020153 | 0.2390996 | 0.2000523 | -0.0460504 | 0.3953366 | 0.7473577 | 0.3383980 | -0.7965949 | -0.7585810 | -0.5744042 | -0.7910817 | -0.3699086 | 0.2304345 | -0.4903971 | -0.3862337 | -0.7777244 | -0.5370240 | -0.6608638 | -0.6590514 | -0.4863910 | -0.8137746 | -0.5261233 | -0.3851721 | -0.5340260 | 0.2083666 | -0.0345297 | 0.3135169 | -0.0421563 | -0.3367977 | -0.9809932 | 0.6149958 | -0.3816823 | -0.7504162 | 0.2150954 | -0.4651303 | 0.9414789 | 0.0183283 | 0.1719831 | -0.0435194 | -0.8446299 | -0.0982949 | -1.1148441 | 0.1636984 | 0.4556204 | 0.5844664 | -0.5138787 | 1.2589879 | -0.1127212 | 0.6246938 | -0.4255173 | -0.4765105 | -0.2640740 | 0.3907860 | 0.5869872 | -0.4971612 |
| 5 | 0.4762315 | -0.0426616 | -0.3565863 | -0.1818158 | 0.1195354 | 0.4432980 | 0.7701842 | 0.6563921 | -0.4073379 | -0.3384438 | -0.1598804 | -0.1797766 | 0.4113771 | -0.0059347 | -0.1682729 | -0.559017 | -0.4651303 | 0.1576482 | 0.7103055 | -0.3400689 | -0.1742276 | -0.3374361 | -0.3521783 | -0.2729603 | 0.0582567 | 0.0991312 | -0.3158907 | -0.1827815 | 0.25 | 0.0229819 | -0.2790782 | -0.4635525 | -0.0154878 | -0.2484579 | -0.2767009 | -0.0650018 | 0.8108916 | 0.6083436 | 0.6690941 | 0.5354034 | 0.6229454 | 0.6331918 | 0.8474527 | 0.7572890 | 0.8109728 | 0.6241561 | 0.3238871 | 0.2119835 | 0.9136662 | 0.8640306 | 0.5708238 | -0.1388164 | -0.1674235 | -0.2481964 | 1.1753875 | 1.1110199 | 1.1935136 | 0.8985540 | 1.1616853 | 1.1260251 | -0.7495858 | -0.4851460 | -0.0100750 | -0.5482666 | -0.7891915 | -0.4734649 | 0.4816798 | -0.4246729 | -0.2292997 | -0.4210014 | -0.1315201 | -0.0148763 | -0.4433349 | 0.0199141 | -0.3381197 | -0.4651303 | -0.4516922 | 0.5515139 | 0.9376818 | -0.1827815 | 0.3344508 | -0.4091584 | -0.0570424 | -0.2021782 | -0.1946718 | 0.0488620 | -0.1408597 | 0.1360367 | 0.9225635 | 0.5684911 | -0.4750829 | -0.4636926 | -0.5584549 | 0.4737008 | -0.1472100 | -0.2627370 |
-> Valores positivos indican que ese grupo (cluster) tiene mayores valores que la media general de esa variable.
-> Valores negativos indican que ese grupo tiene valores inferiores a la media general.
# Quitamos la columna "cluster" para aplicar la lógica solo a las variables numéricas
perfiles_sin_cluster <- perfiles %>% dplyr::select(-cluster)
# Creamos un resumen con el número de veces que está por encima o debajo de la media
conteo_cluster <- perfiles_sin_cluster %>%
mutate(cluster = perfiles$cluster) %>%
rowwise() %>%
mutate(
por_encima = sum(c_across(everything()) > 0, na.rm = TRUE),
por_debajo = sum(c_across(everything()) < 0, na.rm = TRUE)
) %>%
dplyr::select(cluster, por_encima, por_debajo)
conteo_cluster
## # A tibble: 5 × 3
## # Rowwise:
## cluster por_encima por_debajo
## <int> <int> <int>
## 1 1 46 51
## 2 2 52 45
## 3 3 42 55
## 4 4 42 55
## 5 5 44 53
conteo_cluster_por <- perfiles_sin_cluster %>%
mutate(cluster = perfiles$cluster) %>%
rowwise() %>%
mutate(
total_vars = ncol(perfiles_sin_cluster),
por_encima = sum(c_across(everything()) > 0, na.rm = TRUE),
por_debajo = sum(c_across(everything()) < 0, na.rm = TRUE),
pct_encima = por_encima / total_vars,
pct_debajo = por_debajo / total_vars
) %>%
dplyr::select(cluster, por_encima, por_debajo, pct_encima, pct_debajo)
conteo_cluster_por
## # A tibble: 5 × 5
## # Rowwise:
## cluster por_encima por_debajo pct_encima pct_debajo
## <int> <int> <int> <dbl> <dbl>
## 1 1 47 51 0.490 0.531
## 2 2 53 45 0.552 0.469
## 3 3 43 55 0.448 0.573
## 4 4 43 55 0.448 0.573
## 5 5 45 53 0.469 0.552
matplot(t(perfiles[,-1]), type = "l", ylab = "medias", lty = 1, lwd = 2,
col = rainbow(5), xlab = "", xaxt = "n")
axis(side = 1, at = 1:ncol(datos_Z), labels = colnames(datos_Z), las = 2, cex.axis = 0.6)
legend("topright", as.character(1:5), col = rainbow(5), lwd = 2, bty = "n")
✅ 1. Extraer las variables que más distinguen los clusters Como estás
trabajando con valores escalados, una buena forma de detectar las
variables más relevantes es calcular la varianza entre clusters para
cada variable:
La varianza mide la dispersión de los valores medios por cada cluster.
-> Una varianza más elevada se traduce en mayores diferencias entre clusters, por lo que nos será más fácil explicar por qué se formaron.
-> Una varianza baja, por otra parte, indicaría que todos los clusters son más o menos iguales en esa variable.
library(dplyr)
library(tidyr)
df_clusters <- data.frame(cluster = clust3$cluster, datos_raw)
# Calculamos varianza entre clusters
variabilidad <- df_clusters %>%
pivot_longer(-cluster, names_to = "variable", values_to = "valor") %>%
group_by(variable) %>%
summarise(varianza = var(valor)) %>%
arrange(desc(varianza))
top_vars <- head(variabilidad, 96)
print(top_vars)
## # A tibble: 96 × 2
## variable varianza
## <chr> <dbl>
## 1 Precio_m2_max_Caro 3799173.
## 2 Precio_m2_max_Medio 358800.
## 3 Precio_m2_max_Barato 278020.
## 4 Precio_m2_sd_Caro 91488.
## 5 Precio_m2_media_Caro 89187.
## 6 Precio_m2_min_Caro 88326.
## 7 Precio_m2_media_Medio 84866.
## 8 CONSTRUCTEDAREA_max_Caro 53622.
## 9 Precio_m2_media_Barato 49098.
## 10 Precio_m2_sd_Barato 19054.
## # ℹ 86 more rows
Las primeras posiciones del ranking están dominadas por variables relacionadas con el PRECIO por m², estas son las variables más discriminantes.
El precio por metro cuadrado, especialmente en viviendas caras, es con diferencia la variable que mejor separa los clusters. Por ello, podemos observar que la segmentación de clusters está fuertemente influenciada por el mercado alto.
Asimismo, el precio por m² en rangos medio y barato contribuye, aunque en menor medida. Las diferencias de precio son estructurales entre grupos.
A estas las siguen las Variables de superficie construida:
CONSTRUCTEDAREA_max_Caro, CONSTRUCTEDAREA_media_Barato, CONSTRUCTEDAREA_sd_Caro, CONSTRUCTEDAREA_min_Caro, CONSTRUCTEDAREA_max_Medio…
Los metros cuadrados con los que cuentan las viviendas (tanto su media como mínima y máxima) aparecen sistemáticamente entre las 30 variables más importantes.
El tamaño de los inmuebles también separa los clusters, especialmente en los extremos del mercado (caro y barato). Además, la variabilidad del tamaño (desviación típica) también tiene su importancia sobre los clusters que agrupan zonas con viviendas más homogéneas frente a las más dispares.
A partir de la fila 25 y hasta más de la mitad de filasm encontramos salteados los Número de baños y habitaciones, contando con variables como:
BATHNUMBER_max_Caro, ROOMNUMBER_max_Caro, BATHNUMBER_sd_Caro, ROOMNUMBER_min_Caro, etc.
El número de habitaciones y baños tiene importancia media-alta. Aunque no discriminan tanto como el precio y el tamaño, aportan información útil y relevante, especialmente en viviendas caras. Seguramente porque existan zonas de lujo que cuenten con viviendas de alta gama, presentando estas un elevado número de baños/dormitorios. La variabilidad interna en el número de baños (desviación típica) también aparece, lo que sugiere heterogeneidad dentro de algunos clusters.
Seguidamente, y de la misma forma que los núm. de habitaciones y baños, encontramos simúltaneamente la Distancia al centro y al metro. Contando con Variables como:
DISTANCE_TO_CITY_CENTER_max_Barato, DISTANCE_TO_CITY_CENTER_media_Caro, etc.
Las distancias al centro y al metro tienen un peso menor en la discriminación de clusters, aunque no es algo que debamos desestimar.
Las variables de distancia aparecen más abajo en el ranking, lo que sugiere que la localización geográfica relativa no es el principal motor del clustering, al menos no directamente.
No diferenciará en gran medida los clusters debido a que nos encontramos en el centro de valencia. Prácticamente todos los pisos contarán con una parada de metro a la que puedan llegar fácilmente y en poco tiempo a pie. De la misma forma, el centro de la ciudad tampoco deberá variar demasiado. Solamente variará entre los pisos que se encuentren explícitamente en el centro, y los que se encuentren en los distritos que lo rodean.
Por último hablaremos del estado del piso (BUILTTYPEID), que cuente con ascensor y los ratios de habitaciones por baño.
Estas se sitúan muy al final, con varianzas bajísimas (~10^-5 o incluso menores). Indicando que estos factores no están diferenciando realmente los clusters. Puede deberse a:
Contamos con poca variabilidad entre distritos en estas variables (casi todos los pisos se encuentran en buen estado, tienen ascensor…)
Nuestro análisis de varianza entre clusters demuestra con claridad que los clusters están definidos principalmente por el mercado inmobiliario:
-> Precio por m² es el mayor factor diferenciador.
-> Le sigue la superficie construida (y su dispersión).
-> El número de habitaciones y baños también ayuda a diferenciar.
-> La localización (distancia al centro o al metro) tiene relevancia secundaria.
-> Elementos como ascensor o el estado del piso tienen escasa capacidad de diferenciación.
Para averiguar que variables distinguen más a cada cluster individualmente, se puede calcular cuánto se desvía cada cluster de la media general por variable (z-score absoluto).
Este ranking_por_cluster nos mostrará un top-5 de variables más extremas por cluster, con su valor absoluto.
df_clusters <- data.frame(cluster = clust3$cluster, datos_Z) # aquí sí que usamos los datos centrados y escalados
ranking_por_cluster <- df_clusters %>%
pivot_longer(-cluster, names_to = "variable", values_to = "valor") %>%
mutate(valor_abs = abs(valor)) %>%
group_by(cluster) %>%
arrange(cluster, desc(valor_abs)) %>%
slice_head(n = 5) # top 5 por cluster
print(ranking_por_cluster)
## # A tibble: 25 × 4
## # Groups: cluster [5]
## cluster variable valor valor_abs
## <int> <chr> <dbl> <dbl>
## 1 1 RHabitacion_Banyo_media_Caro 2.69 2.69
## 2 1 BATHNUMBER_media_Caro 2.56 2.56
## 3 1 CONSTRUCTEDAREA_min_Medio 2.50 2.50
## 4 1 Precio_m2_max_Medio -2.40 2.40
## 5 1 Precio_m2_min_Caro 2.14 2.14
## 6 2 DISTANCE_TO_METRO_min_Medio 3.58 3.58
## 7 2 Precio_m2_min_Barato 3.20 3.20
## 8 2 DISTANCE_TO_METRO_min_Barato 2.64 2.64
## 9 2 RHabitacion_Banyo_min_Medio 2.60 2.60
## 10 2 CONSTRUCTEDAREA_max_Barato -2.58 2.58
## # ℹ 15 more rows
🟥 Cluster 1 – Perfil de proximidad + mercado intermedio asequible -> “Benimaclet” “Jesús”
Viviendas caras con muchos baños y buena relación baño-habitación.
Viviendas medias con tamaño mínimo alto → incluso las más pequeñas son razonablemente grandes.
Precio máximo en rango medio bajo → zona con mercado de gama media contenida, sin picos especulativos.
Cluster 1 parece caracterizar zonas bien equipadas, con buena distribución y tamaño, especialmente en la gama media y cara, pero con precios moderados. Podría ser un perfil de barrios familiares consolidados, de clase media-alta funcional, más que zonas de lujo.
🟨 Cluster 2 – Desviaciones en tamaño y distribución interna -> “Camins al Grau” “Campanar”
Viviendas baratas y medias alejadas del metro.
En viviendas medias, los ratios habitación/baño son más altos → posible infra-dotación de servicios.
En viviendas baratas, el tamaño máximo es bajo, lo cual sugiere homogeneidad hacia el pequeño tamaño.
Cluster 2 representa zonas menos conectadas y con viviendas más pequeñas y menos equipadas, incluso en la gama media. Podría corresponder a barrios periféricos de clase media-baja o zonas tradicionales no reformadas, con poca accesibilidad y precios aún no tensionados.
🟦 Cluster 3 – Perfil de viviendas variadas pero con superficie reducida -> Ciutat Vella” “El Pla del Real” “Extramurs” “L’Eixample”
Muy pocos baños y habitaciones en viviendas medias y baratas.
Alta variabilidad interna en los caros (relación habitación/baño dispersa) y en superficies en media.
Dificultad para identificar un tamaño “típico”, posiblemente por alta heterogeneidad constructiva.
Cluster 3 parece representar zonas con una mezcla de construcciones viejas, nuevas o reformadas, tamaño reducido y gran heterogeneidad. Podría corresponder a barrios céntricos antiguos o zonas gentrificadas parcialmente, donde coexisten diferentes perfiles de vivienda.
🟪 Cluster 4 – Viviendas con superficies variables y precio elevado -> “Algirós” “L’Olivereta” “Patraix”
Alta dispersión de superficie y precio en viviendas caras → mercado inmobiliario muy heterogéneo.
Pocas habitaciones medias en la gama cara → puede haber muchas viviendas pequeñas de lujo.
El tipo de construcción más frecuente (BUILTYPED_1, probablemente edificio completo) predomina tanto en barato como en caro.
Cluster 4 refleja zonas con presencia de mercado inmobiliario tensionado y de lujo, pero muy disperso en tamaño y precio. Indica un área en la que puede haber tanto pisos muy caros pequeños como viviendas grandes con precio medio, posiblemente zonas de inversión y especulación.
🟩 Cluster 5 – Aislamiento relativo + fuerte protagonismo del metro -> “Benicalap” “La Saïdia” “Poblats Marítims” “Quatre Carreres” “Rascanya”
Zonas donde el acceso al metro es muy desigual y generalmente alejado, en todos los rangos de precio.
La media de ascensor en vivienda cara es muy baja, lo cual sugiere construcciones antiguas o de bajo nivel de servicios, incluso en el rango superior.
Cluster 5 representa zonas con baja accesibilidad al transporte público y déficits en equipamiento moderno, incluso en viviendas de precio alto. Puede tratarse de zonas urbanas periféricas o consolidadas pero envejecidas, donde no ha llegado la renovación de infraestructuras.
Precio por m² Cluster 1 (bajo), Cluster 4 (disperso) Tamaño/Distribución Cluster 2 y 3 (pocos baños, tamaño bajo) Equipamiento Cluster 5 (sin ascensor, baja conectividad) Variabilidad interna Cluster 3 y 4 (alta dispersión en caro)
Dibujar mapa de valencia, por distritos y cada distritos pintado por el cluster correspondiente
library(sf)
library(dplyr)
library(stringr)
library(stringi) # para quitar tildes y diéresis
library(ggplot2)
# 1) Carga del GeoJSON bruto
url_geo <- "https://valencia.opendatasoft.com/explore/dataset/districtes-distritos/download/?format=geojson&timezone=Europe/Madrid&lang=es"
distritos_raw <- st_read(url_geo, quiet = TRUE)
# 2) Normalizar nombres: – quitar tildes/diéresis – pasar a MAYÚSCULAS – eliminar "LA " al principio – quitar espacios sobrantes
distritos_sf <- distritos_raw %>%
mutate(
nombre_clean = nombre %>%
stri_trans_general("Latin-ASCII") %>% # convierte “Jesús”→“Jesus”, “Saïdia”→“Saidia”
str_to_upper() %>%
str_remove("^LA\\s+") %>% # quita “LA ” si existe
str_squish()
) %>%
group_by(nombre_clean) %>%
summarise(geometry = st_union(geometry), .groups = "drop") %>%
st_as_sf()
# 3) Prepara tu tabla de clusters; aplica el mismo limpieza de nombre:
distr_cluster <- tibble(
DISTRITO = rownames(datos_Z),
CLUSTER = factor(clust3$cluster)
) %>%
mutate(
DISTRITO_clean = DISTRITO %>%
stri_trans_general("Latin-ASCII") %>%
str_to_upper() %>%
str_remove("^LA\\s+") %>%
str_squish()
)
# 4) Une por el nombre limpio
distritos_map <- distritos_sf %>%
left_join(distr_cluster, by = c("nombre_clean" = "DISTRITO_clean"))
# 5) Pinta todo Valencia
ggplot(distritos_map) +
geom_sf(aes(fill = CLUSTER), color = "white", size = 0.2) +
scale_fill_brewer(palette = "Set2", na.value = "grey80") +
labs(
title = "Valencia: Distritos coloreados por Cluster",
subtitle = "Clusters k-means",
fill = "Cluster"
) +
theme_minimal(base_size = 14) +
theme(
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank()
)