¿Cómo se explican los precios de la vivienda en San Isidro?

El objetivo del presente trabajo es analizar los precios de las viviendas en el Partido de San Isidro con el fin deteminar las condicionantes que lo modifican.

   

1. Estudio de la base de datos de inmuebles en venta

 

Este trabajo utiliza los datos de Properati. Los datos fueron descargados el día 19/06/2020

¿Qué contienen los datos descargados?

datos_properati <- read.csv("ar_properties.csv", 
                            encoding = "UTF-8", 
                            stringsAsFactors = FALSE)
names(datos_properati)
##  [1] "id"              "ad_type"         "start_date"      "end_date"       
##  [5] "created_on"      "lat"             "lon"             "l1"             
##  [9] "l2"              "l3"              "l4"              "l5"             
## [13] "l6"              "rooms"           "bedrooms"        "bathrooms"      
## [17] "surface_total"   "surface_covered" "price"           "currency"       
## [21] "price_period"    "title"           "description"     "property_type"  
## [25] "operation_type"

Se observa en el dataset que la variable l3 hace referencia a los partidos. A partir de ella, se seleccionan los datos del Partido de San Isidro.

prop_si <- datos_properati %>%
  filter(l3 == "San Isidro")

En el dataset original hay observaciones sin partido. ¿Alguna pertenece a San Isidro? Para esto se utiliza la información en el título y en la descripción

sin_partido <- datos_properati %>%
  filter(l3 == "" & l2 == "Bs.As. G.B.A. Zona Norte")

grep("isidro", sin_partido$title)
## integer(0)
grep("isidro", sin_partido$description)
## integer(0)

Dado que ni en el título ni en la descripción se encuentra la palabra “isidro”, se puede estimar que de las 2949 observaciones sin partido en la Zona Norte del Gran Buenos Aires, ninguna de ellas pertenecería a San Isidro.

¿Cuantos días pasaron entre en la primer públicación y la última?

max(ymd(prop_si$created_on)) - min(ymd(prop_si$created_on))
## Time difference of 389 days

 

¿Cómo se distribuye en el tiempo los avisos publicados?

prop_si %>%
  mutate(created_on = ymd(created_on), 
         year = year(created_on), 
         month = month(created_on), 
         mes = case_when(
           month <10 ~ paste0("0", month), 
           TRUE ~ as.character(month)) , 
         periodo = paste0(year, mes)) %>%
  
  ggplot() + 
  geom_bar(aes(x= (periodo)),  color= "black") + 
  labs(title = "Cantidad de avisos publicados en San Isidro", 
       subtitle = "Alquiler y Venta", 
       x = "Periodo", 
       y = "Cantidad de avisos", 
       caption = "Fuente: Properati") +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

   

¿Cuáles fueron los 5 días con más publicaciones de avisos?

prop_si %>%
  mutate(fecha = ymd(created_on)) %>%
  group_by(fecha) %>%
  summarise(cantidad = n()) %>% 
  arrange(desc(cantidad)) %>%
  top_n(5) %>%
  mutate(dia = weekdays(fecha)) %>%
  select(fecha, dia, cantidad) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = T, 
                position = "left")
## Selecting by cantidad
fecha dia cantidad
2019-05-31 viernes 270
2019-08-13 martes 186
2019-10-12 sábado 178
2019-05-30 jueves 157
2019-12-05 jueves 153

   

¿Qué tipo de operaciones se realizaron y en qué moneda?

 prop_si %>%
  group_by(operation_type, currency) %>%
  summarise(cantidad = n()) %>%
  
  rename(Transaccion = operation_type) %>%
    spread(currency,
         value = cantidad) %>%
  rename(`Sin Especificar` = V1) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = T, 
                position = "left")
Transaccion Sin Especificar ARS USD
Alquiler 95 5060 1067
Alquiler temporal 10 431 370
Venta 114 40 9321

 
¿Cuáles son los tipos de propiedades que se comercializaron?

 prop_si %>%
  group_by(operation_type, property_type) %>%
  summarise(cantidad = n()) %>%
  
  rename(Transaccion = operation_type) %>%
    spread(property_type,
         value = cantidad) %>%

  kable() %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = T, 
                position = "left")
Transaccion Casa Casa de campo Cochera Departamento Depósito Local comercial Lote Oficina Otro PH
Alquiler 1765 NA 51 2400 92 672 23 777 75 367
Alquiler temporal 690 NA NA 105 NA 1 NA 3 1 11
Venta 4299 3 170 2952 60 397 661 287 96 550

       

2. Precios de las propiedades residenciales

 

A los efectos de evaluar como se construye el precio de la vivienda, solo se tendrán en cuanta los datos de venta en USD de inmuebles con destino residencial.  

Considerando que posteriormente la localización geográfica será utilizada, también se filtran las observaciones que no tienen coordenadas geográficas. Se convierten las variables a sf.

prop_si_geo <- prop_si %>%
  filter(operation_type == "Venta", currency == "USD", 
         property_type %in% c("Casa", "Casa de campo", "Departamento", "PH"), 
         !is.na(lat) & !is.na(lon)) %>%
    st_as_sf(coords = c("lon", "lat"), crs = 4326)

  Se verifica que todas las propiedades se encuentren en el partido.

limites_si <- getbb("Partido de San Isidro, Buenos Aires", format_out = "sf_polygon")
pal <- colorFactor(c("#8dd3c7", "#ffffb3", "#bebada", "#fb8072"), 
                   domain = c("Casa", "Casa de campo", "Departamento", "PH"))
leaflet() %>% 
  addTiles() %>%
  addPolygons(data= limites_si, fillOpacity = .3, color = "black", stroke = FALSE) %>%
  addCircleMarkers(data = prop_si_geo,
    color = ~pal(property_type),
    stroke = FALSE, 
    popup = paste("Tipo", prop_si_geo$property_type, "<br>",
                  "Precio:", prop_si_geo$price, " USD", "<br>",
                  "M2 cubiertos:", prop_si_geo$surface_covered, "<br>",
                  "Publicado el:", prop_si_geo$created_on)
  )

Algunas propiedades se encontrarían por fuera del partido. A continuación se muestra un mapa estatíco que refleja de manera más evidente esta situación.

ggplot() +
  geom_sf(data = limites_si, alpha = 0.5 ) + 
  geom_sf(data = prop_si_geo) + 
     labs(title = "Propiedades residenciales en venta",
         subtitle = paste0("Propiedades publicadas entre: ", 
                           min(ymd(prop_si$created_on)), " y ",  max(ymd(prop_si$created_on))), 
         caption= "Fuente: Properati 2020",
         y="",
         x="") + 

  theme_void()

 

Efectivamente hay propiedades fuera del partido. Se genera una variable para las parcelas dentro_si para detectar las parcelas que se encuentran dentro de los límites del partido.

prop_si_geo <- prop_si_geo %>%
  mutate(dentro_si = st_intersects(prop_si_geo, limites_si, sparse = FALSE)) %>%
  filter(dentro_si == TRUE) %>%
  select(-dentro_si)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
ggplot() +
  geom_sf(data = limites_si, alpha = 0.5 ) + 
  geom_sf(data = prop_si_geo) + 
     labs(title = "Propiedades residenciales en venta",
         subtitle = paste0("Propiedades publicadas entre: ", 
                           min(ymd(prop_si$created_on)), " y ",  max(ymd(prop_si$created_on))), 
         caption= "Fuente: Properati 2020",
         y="",
         x="") + 
  theme_void()

 

¿Cómo se distribuyen los precios de estos inmuebles?

prop_si_geo %>% 
  ggplot() + 
  geom_boxplot(aes(x = property_type, y = price)) + 
  labs(title = "Distribución del precio de la vivieda", 
       y = "Precio (USD)", 
       x= "Tipo de propiedad", 
       caption =  "Fuente: Properati 2020") + 
    scale_y_continuous(labels = comma) + 
  theme_minimal()

   

En primer lugar, se realiza una regresión simple explicando el precio de la vivienda (price) según su superficie total (surface_total)

prop_si_geo %>% 
  ggplot() + 
  geom_point(aes(x = surface_total, y = price)) + 
  labs(title = "Relación entre superficie y precio", 
       y = "Precio (USD)", 
       x= "Superficie Total", 
       caption =  "Fuente: Properati") +
      scale_y_continuous(labels = comma) + 
  theme_minimal()
## Warning: Removed 946 rows containing missing values (geom_point).

 

regresion1 <- lm(price ~ surface_total, prop_si_geo)

export_summs(regresion1)
Model 1
(Intercept)364815.03 ***
(7599.64)   
surface_total233.02 ***
(10.65)   
N4042       
R20.11    
*** p < 0.001; ** p < 0.01; * p < 0.05.

Como vemos, el R2 es muy bajo: se explican muy pocos precios.

A fin de optimizar el modelo, se incorporan variables:  

  • la variable dependiente es el precio en USD (price)
  • las variables predictoras son la cantidad de ambientes (rooms), la cantitad de dormitorios (bedrooms), la cantidad de baños (bathrooms), la superficie cubierta (surface_covered), la superficie total (surface_total) y el tipo de propiedad (property_type).
regresion2 <- lm(price ~ rooms + bedrooms + bathrooms + surface_covered + surface_total + property_type,
                 prop_si_geo)
export_summs(regresion2)
Model 1
(Intercept)-62413.52 *  
(30188.62)   
rooms31788.53 ** 
(10316.25)   
bedrooms-7810.65    
(13832.51)   
bathrooms135647.37 ***
(9028.52)   
surface_covered370.84 ***
(35.71)   
surface_total14.53    
(8.00)   
property_typeDepartamento5208.76    
(19118.55)   
property_typePH-81765.81 ***
(23476.79)   
N1668       
R20.42    
*** p < 0.001; ** p < 0.01; * p < 0.05.

El resumen de la regresión también se podría visualizar con la función summary().

summary(regresion2)
## 
## Call:
## lm(formula = price ~ rooms + bedrooms + bathrooms + surface_covered + 
##     surface_total + property_type, data = prop_si_geo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2838265   -82093   -11344    52560  5512993 
## 
## Coefficients:
##                             Estimate Std. Error t value             Pr(>|t|)
## (Intercept)               -62413.516  30188.624  -2.067             0.038846
## rooms                      31788.530  10316.249   3.081             0.002094
## bedrooms                   -7810.647  13832.508  -0.565             0.572382
## bathrooms                 135647.372   9028.522  15.024 < 0.0000000000000002
## surface_covered              370.843     35.706  10.386 < 0.0000000000000002
## surface_total                 14.533      7.999   1.817             0.069436
## property_typeDepartamento   5208.762  19118.549   0.272             0.785313
## property_typePH           -81765.807  23476.789  -3.483             0.000509
##                              
## (Intercept)               *  
## rooms                     ** 
## bedrooms                     
## bathrooms                 ***
## surface_covered           ***
## surface_total             .  
## property_typeDepartamento    
## property_typePH           ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 277200 on 1660 degrees of freedom
##   (3320 observations deleted due to missingness)
## Multiple R-squared:  0.4202, Adjusted R-squared:  0.4178 
## F-statistic: 171.9 on 7 and 1660 DF,  p-value: < 0.00000000000000022

Con esta segunda regresión, el R2 aumenta considerablemente en relación a la primer regresión. Sin embargo, sigue siendo bajo. Al incorporar la zonificación, ¿se podría ajustar mejor el modelo?

         

3. Efectos de la zonificación.

 

Michael Manville, Paavo Monkkonen y Michael Lens, postulan en su artículo It’s Time to End Single-Family Zoning que no deberia existir la zonificación donde solo se permita la vivienda unifamiliar (R1 en Estados Unidos). Esta zonificación genera aumento de precio, exclusión, segregación, y no se aprovecha la infraestructura de la ciudad.  

En este sentido, ¿cómo está zonificado el suelo en San Isidro? Según el Plano de Zonificación del Partido y el Código de Ordenamiento Urbano, se observa una predominancia de usos residenciales.

Plano de zonificación

Plano de zonificación

Se redibuja el plano de zonificación del partido de San Isidro y se asignan los colores.

ggplot() +
  geom_sf(data = zonificacion, aes(fill= ZONA)) +
  scale_fill_manual(values = c(
    "APP1" = "gray71", 
    "APP2" = "gray71", 
    "AR" = "grey87", 
    "Ca1" = "salmon", 
    "Cb1" = "salmon",  
    "Cb2" = "salmon",  
    "CE1" = "rosybrown1", 
    "Cm1" = "salmon",  
    "Cm2" = "salmon",  
    "Cm3" = "salmon",  
    "Cm4" = "salmon",  
    "Cm5" = "salmon", 
    "Cma1" = "salmon", 
    "Cma2" = "salmon", 
    "Cma3" = "salmon", 
    "Cma4" = "salmon", 
    "Cmb1" = "salmon", 
    "Cmb3" = "salmon",
    "CmbB" = "salmon",
    "CR1" = "sandybrown",  
    "DUP1" = "grey87", 
    "E" =  "seagreen",   
    "EC" = "palegreen1"   ,
    "EH" = "honeydew1",
    "EPR" =  "honeydew1",  
    "ES" = "lightskyblue",
    "ID" = "plum2", 
    "IE" = "plum2", 
    "IN" = "plum2",   
    "Ra1" = "khaki3",  
    "Ra2"  = "khaki3",  
    "Ra3"  = "khaki3",  
    "Rb1" = "lightgoldenrodyellow",   
    "Rb2" = "lightgoldenrodyellow",   
    "Rb3" = "lightgoldenrodyellow", 
    "Rb4" = "lightgoldenrodyellow",  
    "RbPN" = "lightgoldenrodyellow", 
    "Rm1" = "khaki1",   
    "Rm2" = "khaki1",   
    "Rm3" = "khaki1",   
    "Rm4" = "khaki1",   
    "Rma" = "khaki1",  
    "Rma1" = "khaki3", 
    "Rma2" = "khaki3", 
    "Rma3" = "khaki3", 
    "Rma4" = "khaki3", 
    "Rma5" = "khaki3", 
    "Rmb1" = "khaki1",  
    "Rmb2" = "khaki1",  
    "Rmb3" = "khaki1",  
    "Rmb4" = "khaki1", 
    "Rmb5" = "khaki1", 
    "RmbB" = "khaki1", 
    "Ru" = "grey87",
    "S" = "lightblue" 

  )) + 
  theme_void() +
  theme(legend.position = "none")

Todas las zonas del partido permiten el uso de vivienda unifamiliar (como uso predominante o como uso complementario). Esto no ocurre para la vivienda multifamiliar.   El uso vivienda multifamiliar es conforme en las siguientes zonas según el cuadro de Usos: Cm2, Ca1, APP2, Rm2, Rma2, Ra1, Ra2, Ra3, Ca1, Cma2, Rm4, Rma1, Rma2, Rma3, Rma5, Cma1, Cma3, Cma4

zonificacion <- zonificacion %>%
  mutate(superficie = st_area(zonificacion),
         permite_multi = ifelse(ZONA %in% c("Cm2", "Ca1", "APP2", "Rm2", "Rma2", "Ra1", "Ra2", "Ra3", "Ca1", "Cma2", "Rm4", "Rma1", "Rma2", "Rma3", "Rma5", "Cma1", "Cma3", "Cma4" ), "si", "no"), 
         zona = ZONA) %>%
  select(zona, superficie, permite_multi)
zonificacion %>%
  mutate(sup_ha = as.numeric(superficie) / 10000) %>%
  st_set_geometry(NULL) %>%
  ggplot() + 
  geom_bar(aes(x = zona, weight = sup_ha, fill = permite_multi)) + 

  labs(title = "Superficie según zona", 
       fill = "¿Permite Multifamiliar?", 
       y = "Superfice (ha)") + 
  theme_minimal() + 
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) 

¿Cómo quedaría entonces la comparación entre superficie disponible para vivienda multifamiliar, y superficie para vivienda unifamiliar?

zonificacion %>%
  mutate(sup_ha = as.numeric(superficie) / 10000) %>%
  st_set_geometry(NULL) %>%
  ggplot() + 
  geom_bar(aes(x = permite_multi, weight = sup_ha, fill = permite_multi)) + 

  labs(title = "Superficie según la posibilidad de construir un edificio multifamiliar", 
       fill = "¿Permite Multifamiliar?", 
       y = "Superfice (ha)", 
       x = "") + 
  
  theme_minimal() 

Es importante aclarar que las superficies en ambos casos incluyen el espacio público (calle, vereda, etc). El objetivo es tener un panorama general.

   

Entonces, en el partido de San Isidro hay poca superficie donde se permite la vivienda multifamiliar.

   

¿En que zonas se ubican las propiedades analizadas?

ggplot() +
  geom_sf(data = prop_si_geo)  +
  geom_sf(data = zonificacion, aes(fill= permite_multi), alpha = 0.5) +
  geom_sf(data = limites_si, fill = NA, alpha = 0.5 ) + 
  labs(title = "Mapa de Zonificación de San Isidro y propiedades en venta",
       fill = "¿Permite Multifamiliar?",
         caption= "Fuente: Properati 2020") + 
  theme_void() 

Se observa en el mapa una mayor extensión de zonas donde no se permite vivienda multifamiliar.    

¿Hay alguna concentración de propiedades en venta? ¿Dónde se ubican los hotspots?

bbox <- getbb('Partido de San Isidro, Buenos Aires')

map_si <- get_stamenmap(bbox, zoom = 12, maptype = 'terrain')
ggmap(map_si)+
stat_density2d(data = prop_si_geo %>% cbind(., st_coordinates(prop_si_geo)), 
               aes(x = X, y = Y, fill = ..density..), 
                geom = 'tile', contour = limites_si, alpha = 0.5) + 
    geom_sf(data = zonificacion %>% filter(permite_multi == "si"),
            aes(color = permite_multi), 
            fill = NA, alpha = 0.5, inherit.aes = FALSE) +
  scale_color_manual(values = "grey") +  
  geom_sf(data = limites_si, fill = NA, alpha = 0.5, size = 2, inherit.aes = FALSE) + 
  labs(title = "Concentración de propiedades en venta",
         caption= "Fuente: Properati 2020", 
       color = "Zonas de multifamiliar", 
       fill = "Densidad") + 
  scale_fill_viridis_c(option = "A") + 
  theme_void() 

Hay una concentración de propiedades en venta principalmente en zonas donde se permiten las viviendas multifamilias, en particular en la zona del centro de Martinez-Acassuso y del centro de San Isidro.

   

Se incorpora la zona correspondiente a cada propiedad a fin de incluir la zonificación en el estudio de regresión.

prop_si_geo_zona <- st_join(prop_si_geo, zonificacion) %>%
  select(-superficie)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar

Se regresan los datos tomando la variable binaria permite_multi (que toma los valores si o no). Y se consideran solo los valores de superficie cubierta, cantidad de ambientes, tipo de propiedad, y si se encuentra en una zona de multifamiliar.

regresion3 <- lm(price ~ 
                   rooms + surface_covered + property_type + permite_multi, prop_si_geo_zona)
export_summs(regresion3)
Model 1
(Intercept)2285.85    
(18223.81)   
rooms55756.71 ***
(3751.66)   
surface_covered1048.05 ***
(32.62)   
property_typeDepartamento21165.14    
(14092.63)   
property_typePH-96147.08 ***
(18699.10)   
permite_multisi-5738.91    
(13292.64)   
N3618       
R20.44    
*** p < 0.001; ** p < 0.01; * p < 0.05.
confint(regresion3)
##                                 2.5 %     97.5 %
## (Intercept)                -33444.131  38015.835
## rooms                       48401.137  63112.284
## surface_covered               984.084   1112.012
## property_typeDepartamento   -6465.160  48795.449
## property_typePH           -132808.933 -59485.230
## permite_multisi            -31800.740  20322.926

Si bien el R2 aumenta en relación a la regresión 2, aún no es suficiente para determinar como se comporta el precio de las viviendas en San Isidro.    

 

 

 

Conclusión

Para resumir, el valor hedónico de los precios de las viviendas se encuentra afectado por distintas variables, de los cuales es importante destacar la superficie y la cantidad de ambientes. La zonificación no parecería incidir de manera significativa en los precios. Con el objetivo de profundizar el presente análisis, sería conveniente incorporar la metodología aplicada por A. Stewart Fotheringham, Chris Brunsdon, Martin Charlton en “Geographically Weighted Regression: The Analysis of Spatially Varying Relationships (2002)” para estudiar el precio de la vivienda en Londres, a fin de evaluar la dependecia espacial.