Introducción

En este trabajo vamos a leer, manipular, transformar, visualizar y analizar distintos datasets del portal de datos abiertos del Gobierno de la Ciudad de Buenos Aires (GCBA) y de Properati a fin de establecer cuáles serían las ubicaciones óptimas de la ciudad de Buenos Aires para utilizar su capacidad hotelera con el propósito de mejorar la atención sanitaria de la población en el marco de la actual pandemia por Covid-19, ofreciendo centros de aislamiento para aquellas personas que no puedan guardarlo en sus domicilios particulares y cuyo cuadro no requiera de una internación hospitalaria. Para realizar dicho análisis construiremos un índice que tome en cuenta los criterios que se enumeran a continuación.

En la primera parte del trabajo importaremos, manipularemos y transformaremos los datos que necesitamos para la construcción del índice, En la segunda elaboraremos el índice propiamente dicho, a partir del análisis de la información obtenida en la primera parte y ofreceremos una visualización de las ubicaciones óptimas de la ciudad para la localización de los centros de aislamiento en base a dicho índice.

1) Criterios de localización

1.1 Costo promedio del alquiler

Comenzamos, como siempre, por activar los paquetes necesarios para las operaciones que vamos a realizar. En este caso, tydiverse, sf y leaflet:

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3     ✓ purrr   0.3.4
## ✓ tibble  3.1.0     ✓ dplyr   1.0.5
## ✓ tidyr   1.1.3     ✓ stringr 1.4.0
## ✓ readr   1.4.0     ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(sf)
## Linking to GEOS 3.8.1, GDAL 3.1.4, PROJ 6.3.1
library(leaflet)

Para calcular el costo promedio del alquiler utilizamos tres datasets: uno de manzanas y uno de barrios, del portal de datos abiertos del GCBA y otro de publicaciones de propiedades alquiler de Properati entre enero de 2020 y julio de 2021. Comenzamos importando los tres datasets y explorando su estructura:

manzanas <- st_read("data/manzanas.geojson")
## Reading layer `manzanas' from data source `/Users/nahuel/Desktop/IAU/data/manzanas.geojson' using driver `GeoJSON'
## Simple feature collection with 12520 features and 12 fields
## Geometry type: POLYGON
## Dimension:     XYZ
## Bounding box:  xmin: -58.53042 ymin: -34.70389 xmax: -58.33514 ymax: -34.52755
## z_range:       zmin: 0 zmax: 49.894
## Geodetic CRS:  WGS 84
glimpse(manzanas)
## Rows: 12,520
## Columns: 13
## $ FeatId1    <int> 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,…
## $ MANZANA    <chr> "074", "056", "110", "035", "109", "124", "138", "104", "10…
## $ SECCION    <chr> "059", "059", "059", "059", "059", "059", "059", "059", "05…
## $ NIVEL      <chr> "15.80", "15.80", "15.80", "15.80", "15.80", "15.80", "15.8…
## $ OBS        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ MZ_TIPO    <chr> "ATIPICA", "ATIPICA", "TIPICA", "TIPICA", "TIPICA", "TIPICA…
## $ CANT_LADOS <int> 3, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ MZ_SUP     <dbl> 1514.829, 16453.152, 14042.663, 14722.159, 11272.537, 14317…
## $ CANT_PA    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ LFI        <chr> "NO", "SI", "SI", "NO", "SI", "SI", "SI", "SI", "NO", "SI",…
## $ LIB        <chr> "NO", "SI", "SI", "SI", "SI", "SI", "SI", "SI", "NO", "SI",…
## $ SM         <chr> "059-074", "059-056", "059-110", "059-035", "059-109", "059…
## $ geometry   <POLYGON [°]> POLYGON Z ((-58.46566 -34.6..., POLYGON Z ((-58.469…
barrios <- st_read("data/barrios_caba.geojson")
## Reading layer `barrios_badata' from data source `/Users/nahuel/Desktop/IAU/data/barrios_caba.geojson' using driver `GeoJSON'
## Simple feature collection with 48 features and 4 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -58.53152 ymin: -34.70529 xmax: -58.33515 ymax: -34.52649
## Geodetic CRS:  WGS 84
glimpse(barrios)
## Rows: 48
## Columns: 5
## $ barrio    <chr> "CHACARITA", "PATERNAL", "VILLA CRESPO", "VILLA DEL PARQUE",…
## $ comuna    <int> 15, 15, 15, 11, 5, 6, 11, 10, 10, 7, 10, 1, 3, 5, 10, 10, 4,…
## $ perimetro <dbl> 7724.853, 7087.513, 8131.857, 7705.390, 8537.901, 10990.964,…
## $ area      <dbl> 3115707, 2229829, 3615978, 3399596, 4050752, 6851029, 215369…
## $ geometry  <POLYGON [°]> POLYGON ((-58.45282 -34.595..., POLYGON ((-58.46558 …
precios_alquileres_original <- read_delim("data/rent_properati_2020_2021.csv",  delim= ",")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   .default = col_character(),
##   start_date = col_date(format = ""),
##   end_date = col_date(format = ""),
##   created_on = col_date(format = ""),
##   lat = col_double(),
##   lon = col_double(),
##   l6 = col_logical(),
##   rooms = col_double(),
##   bedrooms = col_double(),
##   bathrooms = col_double(),
##   surface_total = col_double(),
##   surface_covered = col_double(),
##   price = col_double()
## )
## ℹ Use `spec()` for the full column specifications.
glimpse(precios_alquileres_original)
## Rows: 194,510
## Columns: 22
## $ ad_type         <chr> "Propiedad", "Propiedad", "Propiedad", "Propiedad", "P…
## $ start_date      <date> 2020-09-13, 2020-09-13, 2020-09-13, 2020-09-13, 2020-…
## $ end_date        <date> 2020-09-14, 2020-10-31, 2020-09-14, 9999-12-31, 9999-…
## $ created_on      <date> 2020-09-13, 2020-09-13, 2020-09-13, 2020-09-13, 2020-…
## $ lat             <dbl> -34.39981, NA, -34.49246, -34.61592, -38.95463, -32.49…
## $ lon             <dbl> -58.63835, NA, -58.57574, -58.41834, -68.11152, -63.40…
## $ l1              <chr> "Argentina", "Argentina", "Argentina", "Argentina", "A…
## $ l2              <chr> "Bs.As. G.B.A. Zona Norte", "Capital Federal", "Bs.As.…
## $ l3              <chr> "Tigre", "Belgrano", "San Isidro", "Neuquén", "NeuquÅ
## $ l4              <chr> NA, NA, NA, NA, NA, "Centro", NA, "Florida", NA, NA, N…
## $ l5              <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ l6              <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ rooms           <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ bedrooms        <dbl> 5, 4, 4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ bathrooms       <dbl> 6, 4, 5, NA, NA, NA, NA, 2, NA, NA, 2, NA, 3, 3, 1, NA…
## $ surface_total   <dbl> 3000, NA, 500, NA, NA, NA, 98, 704, 200, 125, 70, 98, …
## $ surface_covered <dbl> 378, 560, 298, NA, NA, NA, 98, 704, 200, 125, 70, 96, …
## $ price           <dbl> 5000, 8000, 1500, 26000, 35000, 4500, 25000, 5600, 600…
## $ currency        <chr> "USD", "USD", "USD", "ARS", "ARS", "ARS", "ARS", "USD"…
## $ price_period    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ property_type   <chr> "Casa", "Casa", "Casa", "Lote", "Lote", "Oficina", "Of…
## $ operation_type  <chr> "Alquiler", "Alquiler", "Alquiler", "Alquiler", "Alqui…

Como vemos se trata de dos dataframes de datos espaciales con un sistema de coordenadas de referencia (CRS) geodésico (WGS) 84 y un dataframe tradicional. Una vez importados los tres dataframes originales procedemos a realizar las transformaciones necesarias:

  • En primer lugar, utilizamos las funciones select() y mutate() para seleccionar nuestras variables de interés del dataframe de alquileres, a partir de las cuales creamos una nueva variable (precio por m2), a fin de volver comparables los precios de alquileres de propiedades de diferentes dimensiones. Habiendo corroborado la existencia de valores extremos, utilizamos la función filter() para eliminarlos de nuestro dataframe, ya que trabajaremos con promedios, que son una medida de tendencia central muy sensible a dichos valores. Asimismo dejamos de lado todas las observaciones que no tienen datos de ubicación (latitud y longitud).
precios_alquileres_por_m2 <- precios_alquileres_original %>% 
                                 select (lat, lon, surface_covered, price, currency) %>% 
                                 mutate (precio = ifelse(currency=="USD", price*100,price*1),                                                   precio_m2=round (price/surface_covered)) %>%
                                 rename (m2_cubiertos=surface_covered ) %>%
                                 select (lat, lon, precio_m2) %>% 
                                 filter (precio_m2<10000, precio_m2>0, !lat=="NA", !lon=="NA")
  • En segundo lugar, transformamos nuestro dataframe de datos tradicionales en un dataframe de datos espaciales mediante la función st_as_sf(), que convierte las variables de longitud y latitud en una única variable de geometrías, a fin de poder unirlo con datos de otros dataframes a partir de su ubicación espacial.
precios_alquileres_por_m2 <- precios_alquileres_por_m2 %>%  
                             st_as_sf(coords=c("lon","lat"), crs=4326)
  • Para filtrar las observaciones correspondientes a la ciudad de Buenos Aires, utilizamos la función st_intersection(). Para ello creamos primero un dataframe espacial del polígono de toda la ciudad a partir del dataframe de barrios, mediante la función st_union(). Filtramos por ubicación espacial en lugar de hacerlo a partir de la variable “I2” de nuestro dataframe de alquileres para no desestimar ni quedarnos equivocadamente con observaciones cuya localidad estuviera erróneamente cargada. Como puede observarse en el mapa que sigue, nos hemos quedado así solamente con los registros relevantes para nuestro análisis.
caba <- barrios %>% 
        st_union () %>% 
        st_as_sf (crs=4326)
## although coordinates are longitude/latitude, st_union assumes that they are planar
precios_alquileres_porm2_caba <- st_intersection(precios_alquileres_por_m2, caba)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
ggplot()+
  geom_sf(data=barrios, color="white")+
  geom_sf(data=precios_alquileres_porm2_caba, color="darkorchid4", alpha=0.1)+
  theme_void() +
   labs(title = "Inmuebles en alquiler en la Ciudad de Buenos aires", 
        subtitle = "Ubicación de los inmuebles ofertados 2020/2021",
        caption = "fuente: Properati")

  • Una vez que contamos con todos los registros de precio de alquileres por metro cuadrado con sus respectivas ubicaciones, procedemos a calcular el precio por metro cuadrado promedio por manzana. Para ello, utilizamos la función st_join() para unir nuestro dataframe de precios de alquileres por metro cuadrado con el dataframe de manzanas, el cual unimos a su vez con el de barrios, ya que como veremos enseguida, precisaremos también este dato. Una vez unidos nuestros dataframes, utilizamos las funciones group_by() y summarise() para calcular el precio promedio del metro cuadrado para cada manzana.
manzanas_con_barrio <- manzanas %>% 
                       st_join(barrios) %>% 
                       select(SM, barrio, geometry)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
precio_promedio_por_manzana <- manzanas_con_barrio %>% 
                               st_join(precios_alquileres_por_m2) %>% 
                               st_set_geometry(NULL) %>%
                               select(barrio, SM, precio_m2) %>% 
                               group_by(barrio, SM) %>% 
                               summarise(precio_m2=mean(precio_m2))
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## `summarise()` has grouped output by 'barrio'. You can override using the `.groups` argument.
  • Como hemos constatado que existen manzanas sin ningún valor para la variable “precio por m2”, lo cual se debe a que no tenemos registros de Properati para esas manzanas, les asignaremos el valor del precio promedio del barrio.
precios_promedio_por_barrio <- precios_alquileres_porm2_caba %>% 
                               st_join(barrios) %>% 
                               st_set_geometry(NULL) %>% 
                               group_by(barrio) %>% 
                               summarise(precio_m2_promedio=mean(precio_m2))
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
precio_promedio_por_manzana_completo <- precio_promedio_por_manzana %>% 
                                        left_join(precios_promedio_por_barrio, by="barrio") %>% 
                                        mutate(precio_promedio_ok = ifelse(is.na(precio_m2),                                                   precio_m2_promedio, precio_m2)) %>% 
                                        select(barrio,SM,precio_promedio_ok)

1.2 Métricas de accesibilidad

Como hemos anticipado, trabajaremos con varios aspectos relativos a la accesibilidad, como la cercanía a avenidas, estaciones de subte y hospitales, a fin de encontrar localizaciones que faciliten tanto la llegada de las personas que deban guardar aislamiento en estos hoteles como su eventual traslado a un hospital, en caso de requerirlo. Para ello utilizaremos tres datasets del portal de datos abiertos del GCBA.

i) Avenidas

Para calcular la distancia a la avenida más cercana necesitamos un nuevo dataset espacial del portal de datos abiertos del GCBA, que importamos y exploramos a continuación, donde podemos encontrar la traza geolocalizada de todas las calles de la ciudad.

calles <- st_read("data/callejero.geojson")
## Reading layer `callejero_badata_WGS84' from data source `/Users/nahuel/Desktop/IAU/data/callejero.geojson' using driver `GeoJSON'
## Simple feature collection with 30712 features and 29 fields
## Geometry type: MULTILINESTRING
## Dimension:     XY
## Bounding box:  xmin: -58.53244 ymin: -34.70574 xmax: -58.34191 ymax: -34.52947
## Geodetic CRS:  WGS 84
glimpse(calles)
## Rows: 30,712
## Columns: 30
## $ id         <int> 28686, 896, 1724, 1729, 1828, 1997, 2062, 3137, 3831, 30056…
## $ codigo     <int> 17138, 16003, 16003, 19028, 16003, 21059, 19053, 16011, 401…
## $ nomoficial <chr> "PUNTA ARENAS", "OBLIGADO RAFAEL, Av.Costanera", "OBLIGADO …
## $ alt_izqini <int> 0, 6182, 4202, 4202, 3452, 0, 0, 2796, 3002, 1172, 2602, 0,…
## $ alt_izqfin <int> 0, 6200, 4500, 4220, 4200, 0, 0, 2800, 3030, 1200, 3100, 0,…
## $ alt_derini <int> 0, 6181, 4201, 4201, 3451, 0, 0, 2795, 3001, 1171, 2601, 32…
## $ alt_derfin <int> 0, 6199, 4499, 4219, 4199, 0, 0, 2799, 3029, 1199, 3099, 32…
## $ nomanter   <chr> NA, "COSTANERA NORTE, Av.", "COSTANERA NORTE, Av.", "REPUBL…
## $ nom_mapa   <chr> "TÚNEL PUNTA ARENAS", "AV.COSTANERA RAFAEL OBLIGADO", "AV.C…
## $ tipo_c     <chr> "TÚNEL", "AVENIDA", "AVENIDA", "AVENIDA", "AVENIDA", "CALLE…
## $ long       <dbl> 334.6034, 56.3800, 297.2600, 30.5900, 175.9300, 9.4000, 14.…
## $ sentido    <chr> "DOBLE", "DOBLE", "DOBLE", "CRECIENTE", "DOBLE", "DOBLE", "…
## $ cod_sent   <int> 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, -1, 1, 1, -1, 1, 1, 2, …
## $ observa    <chr> "Viaducto - Túnel inaugurado en Abril de 2009", NA, NA, NA,…
## $ bicisenda  <chr> "-", "Ciclovías", "Ciclovías", "-", "Ciclovías", "Ciclovías…
## $ lado_ciclo <chr> NA, NA, NA, NA, NA, "Por calzada paralela y adyacente a la …
## $ recorrid_x <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "Vereda", NA, NA, N…
## $ ciclo_obse <chr> NA, "Construcción Año 2014", "Construcción Año 2014", NA, "…
## $ tooltip_bi <chr> NA, "Ciclovía", "Ciclovía", NA, "Ciclovía", "Ciclovía", NA,…
## $ red_jerarq <chr> "VÍA DISTRIBUIDORA COMPLEMENTARIA", "VÍA DISTRIBUIDORA PRIN…
## $ red_tp     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, "SI", NA, NA, "SI", NA,…
## $ ffcc       <chr> "SI", NA, NA, "SI", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ tipo_ffcc  <chr> "Túnel", NA, NA, "Paso a Nivel", NA, NA, NA, NA, NA, NA, NA…
## $ COMUNA     <int> 15, 13, 14, 12, 14, 12, 12, 13, 14, 2, 14, 12, 13, 2, 2, 2,…
## $ COM_PAR    <int> 15, 13, 14, 12, 14, 12, 12, 13, 14, 2, 14, 12, 13, 2, 2, 2,…
## $ COM_IMPAR  <int> 15, 13, 14, 12, 14, 12, 12, 13, 14, 2, 14, 12, 13, 2, 2, 2,…
## $ BARRIO     <chr> "PATERNAL", "PALERMO", "PALERMO", "SAAVEDRA", "PALERMO", "C…
## $ BARRIO_PAR <chr> "PATERNAL", "PALERMO", "PALERMO", "SAAVEDRA", "PALERMO", "C…
## $ BARRIO_IMP <chr> "PATERNAL", "PALERMO", "PALERMO", "SAAVEDRA", "PALERMO", "C…
## $ geometry   <MULTILINESTRING [°]> MULTILINESTRING ((-58.4694 ..., MULTILINEST…
  • Una vez importado nuestro dataframe espacial de calles, lo fitramos para quedarnos solamente con las avenidas:
avenidas <- filter(calles, tipo_c=="AVENIDA")
  • Para calcular las distancias, utilizamos la función st_distance(), la cual nos arroja un vector con las distancias entre las geometrías de cada observación de un dataframe y otro. Para ello, necesitamos realizar previamente algunas transformaciones. Como hemos visto más arriba, nuestros dataframes se encuentran en un CRS geodésico (GWS 84). Para utilizar esta función necesitamos transformarlos a un CRS proyectado. Asimismo, para simplificar la cantidad de operaciones a realizar, en lugar de considerar la distancia entre cada punto del polígono de cada manzana y cada tramo de cada avenida, consideramos solamente la distancia a ellos desde el centro de aquéllas. Para ello utilizamos la función st_centroid() y creamos un nuevo dataframe, cuya columna de geometría contiene la ubicación de este punto. Pero además, como lo que nos interesa no es la distancia que existe entre el centro de cada manzana y todos los tramos de cada avenidas sino solamente respecto de la más cercana, utilizamos la función aply() que nos arroja un vector con las distancias mínimas de cada centro de manzana a una avenida.
avenidas <- st_transform(avenidas, crs="+proj=tmerc +lat_0=-34.6297166 +lon_0=-58.4627 +k=1 +x_0=100000 +y_0=100000 +ellps=intl +units=m +no_defs")
manzanas <- manzanas %>% 
            st_transform(crs = st_crs(avenidas)) %>% 
            select(SM,geometry)
manzanas_centroides <- st_centroid (manzanas)
## Warning in st_centroid.sf(manzanas): st_centroid assumes attributes are constant
## over geometries of x
distancia_avenidas <- st_distance(manzanas_centroides,avenidas)
avenida_mas_cercana <- round(apply(distancia_avenidas,1,function(x) min(x)),0)
  • Una vez obtenido este valor (distancia mínima de cada centro de manzana a una avenida) lo incorporamos a nuestro dataframe original de manzanas, creando una nueva variable (distancia a la avenida más cercana):
manzanas <- mutate(manzanas, distancia_av_mas_cercana=avenida_mas_cercana)

ii) Estaciones de subte

Luego repetimos las mismas operaciones para calcular la distancia a la estación de subte más cercana. Para ello utilizamos otro dataset espacial del portal de datos abiertos del GCBA con las ubicaciones de todas las estaciones de subte.

subte_estaciones <- st_read("data/subte_lineas.geojson")
## Reading layer `subte_lineas' from data source `/Users/nahuel/Desktop/IAU/data/subte_lineas.geojson' using driver `GeoJSON'
## Simple feature collection with 82 features and 2 fields
## Geometry type: MULTILINESTRING
## Dimension:     XY
## Bounding box:  xmin: -58.48639 ymin: -34.64331 xmax: -58.36987 ymax: -34.55564
## Geodetic CRS:  WGS 84
glimpse(subte_estaciones)
## Rows: 82
## Columns: 3
## $ ID       <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18…
## $ LINEASUB <chr> "LINEA D", "LINEA D", "LINEA D", "LINEA D", "LINEA D", "LINEA…
## $ geometry <MULTILINESTRING [°]> MULTILINESTRING ((-58.45213..., MULTILINESTRI…
subte_estaciones <- st_transform(subte_estaciones, crs = st_crs(avenidas))
distancia_subte <- st_distance(manzanas_centroides,subte_estaciones)
estacion_mas_cercana <- round(apply(distancia_subte,1,function(x) min(x)))
manzanas <- mutate (manzanas, distancia_estacion_mas_cercana=estacion_mas_cercana)

iii) Hospitales

Como último criterio de accesibilidad, consideramos la cobertura hospitalaria. Para ello utilizamos otro dataset del portal de datos abiertos del GCBA, con la localización de los 36 hospitales de la ciudad:

hospitales <- read_delim("data/Hospitales.csv", delim= ";")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   .default = col_character(),
##   long = col_double(),
##   lat = col_double(),
##   calle_altura = col_double(),
##   calle_altura_2 = col_double(),
##   codigo_postal = col_double(),
##   camas_medicina = col_double(),
##   camas_cirugía = col_double(),
##   camas_pediatría = col_double(),
##   camas_tocoginecología = col_double(),
##   camas_urgencia = col_double(),
##   camas_otra = col_double(),
##   camas_totales = col_double()
## )
## ℹ Use `spec()` for the full column specifications.
glimpse(hospitales)
## Rows: 36
## Columns: 33
## $ long                    <dbl> -58.37755, -58.41207, -58.40273, -58.38516, -5…
## $ lat                     <dbl> -34.62885, -34.59419, -34.58453, -34.63940, -3…
## $ nombre                  <chr> "HOSPITAL GENERAL DE NIÑOS PEDRO DE ELIZALDE",…
## $ nom_map                 <chr> "HOSP. DE ELIZALDE", "HOSP. GUTIERREZ", "HOSP.…
## $ objeto                  <chr> "HOSPITAL", "HOSPITAL", "HOSPITAL", "HOSPITAL"…
## $ calle_nombre            <chr> "MANUEL A. MONTES DE OCA", "GALLO", "SANCHEZ D…
## $ calle_altura            <dbl> 40, 1330, 2529, 2570, 2061, 4821, 849, 315, 37…
## $ calle_altura_1          <chr> "MANUEL A. MONTES DE OCA 40", "GALLO 1330", "S…
## $ dom_geo                 <chr> "40 MONTES DE OCA, MANUEL AV.", "1330 GALLO", …
## $ telefono                <chr> "4307-5842 / 5844", "4962-9247 / 9248 / 9280",…
## $ guardia                 <chr> "4307-5442 / 4300-1700", "4962-9232", "4805-64…
## $ fax                     <chr> "4302-7400", "4962-3762", "4805-7533", "4303-3…
## $ web                     <chr> "www.elizalde.gov.ar", "www.guti.gov.ar", NA, …
## $ tipo                    <chr> "Hospital de niños", "Hospital de niños", "Hos…
## $ tipo_espec              <chr> "PEDIATRIA", "PEDIATRIA", "ODONTOLOGIA", "SALU…
## $ mod_at_1                <chr> "AT. AMB./INTERNACION", "AT. AMB./INTERNACION"…
## $ mod_at_2                <chr> "DIAG./TRATAM.", "DIAG./TRATAM.", "DIAG./TRATA…
## $ depend_adm              <chr> "Ministerio de Salud GCBA", "Ministerio de Sal…
## $ director                <chr> "Dr. Javier Indart", "Dra. María Cristina Galo…
## $ dom_norma               <chr> "MONTES DE OCA, MANUEL AV. 40", "GALLO 1330", …
## $ calle_altura_2          <dbl> 40, 1330, 2529, 2570, 2061, 4821, 849, 315, 37…
## $ calle_altura_3          <chr> "MANUEL A. MONTES DE OCA 40", "GALLO 1330", "S…
## $ barrio                  <chr> "Barracas", "Recoleta", "Recoleta", "Barracas"…
## $ comuna                  <chr> "Comuna 4", "Comuna 2", "Comuna 2", "Comuna 4"…
## $ codigo_postal           <dbl> 1270, 1425, 1425, 1287, 1264, 1405, 1272, 1275…
## $ codigo_postal_argentino <chr> "C1270AAN", "C1425EFD", "C1425DUY", "C1287ABJ"…
## $ camas_medicina          <dbl> 7.336986, 169.665753, NA, 865.950685, 38.89315…
## $ camas_cirugía           <dbl> NA, 119.347945, NA, 32.000000, 33.079452, NA, …
## $ camas_pediatría         <dbl> NA, NA, NA, NA, NA, NA, NA, 64.00000, NA, NA, …
## $ camas_tocoginecología   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 96…
## $ camas_urgencia          <dbl> NA, 24.619178, NA, NA, 6.082192, NA, 7.652055,…
## $ camas_otra              <dbl> 210.9205, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ camas_totales           <dbl> 218.25753, 313.63288, NA, 897.95068, 78.05479,…
  • Como se trata de un dataframe tradicional, debemos en primer lugar convertirlo en un dataframe de datos espaciales. Pero como además realizaremos operaciones para medir distancias, debemos también transformar el CRS de nuestro dataframe espacial de geodésico a proyectado.
hospitales <- hospitales %>% 
              st_as_sf (coords=c("long","lat"), crs=4326) %>%  
              st_transform (crs="+proj=tmerc +lat_0=-34.6297166 +lon_0=-58.4627 +k=1 +x_0=100000 +y_0=100000 +ellps=intl +units=m +no_defs")
  • En segundo lugar, seleccionamos nuestras variables de interés y descartamos las observaciones correspondientes a los hospitales que solamente cuentan con atención ambulatoria:
hospitales <- hospitales %>% 
              select (nombre,mod_at_1,barrio,comuna,camas_totales,geometry) %>% 
              filter (!mod_at_1=="AT. AMBULATORIA") 
  • En tercer lugar, utilizamos la función st_buffer() para calcular un radio de cobertura de un kilómetro y colapsamos todas las geometrías en una sola. En el mapa que sigue puede observarse el resultado obtenido.
cobertura_hospitales <- st_buffer(hospitales,dist=1000) 
cobertura_hospitales <- cobertura_hospitales %>% summarise(cobertura=TRUE)
ggplot() +
  geom_sf(data=barrios, color="white")+
  geom_sf(data=cobertura_hospitales, fill="darkorchid4", color="darkorchid4", alpha=0.5)+
  theme_void() +
  labs(title = "La Cobretura hospitalaria de la ciudad", 
       subtitle = "Radio de cobertura de hospitales con unidades de internación (hasta 1km)",
       caption ="Fuente: datos abiertos del GCBA")

  • Por último, unimos nuestro dataframe de cobertura al de manzanas a fin de agregar una nueva variable a éste que indique si cada una de las manzanas de la ciudad se encuentra o no en el radio de diez cuadras de cobertura de algún hospital. Una vez que hemos finalizado de realizar operaciones con distancias podemos volver a transformar nuestro dataframe a un CRS geodésico, para poder unirlo espacialmente con el resto de nuestros datos.
cobertura_por_manzana_con_distancias <- manzanas %>% 
                                        st_join(cobertura_hospitales) %>% 
                                        st_transform(crs=4326)

1.3 Densidad Poblacional

Finalmente, trabajamos con la variable densidad poblacional con el propósito de establecer cuáles son los lugares de la ciudad más propicios para la circulación y el contagio del virus, entendiendo que ésta puede ser un factor de riesgo determinante en este sentido. A su vez, comprendemos que una mayor densidad poblacional puede expresar, en algunos casos, condiciones de hacinamiento, las cuales redundan en mayores dificultades para que las personas con contactos estrechos o síntomas puedan cumplir con los protocolos de aislamiento y cuidado. Para esto utilizamos otro dataset del portal de datos abiertos del GCBA, con datos demográficos de todos los radios censales.

radios_censales <- st_read("data/caba_radios_censales.geojson")
## Reading layer `CABA_rc' from data source `/Users/nahuel/Desktop/IAU/data/caba_radios_censales.geojson' using driver `GeoJSON'
## Simple feature collection with 3554 features and 8 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -58.53092 ymin: -34.70574 xmax: -58.33455 ymax: -34.528
## Geodetic CRS:  WGS 84
glimpse(radios_censales)
## Rows: 3,554
## Columns: 9
## $ RADIO_ID    <chr> "1_1_1", "1_12_1", "1_12_10", "1_12_11", "1_12_2", "1_12_3…
## $ BARRIO      <chr> "RETIRO", "SAN NICOLAS", "SAN NICOLAS", "SAN NICOLAS", "SA…
## $ COMUNA      <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"…
## $ POBLACION   <dbl> 336, 341, 296, 528, 229, 723, 393, 600, 472, 786, 329, 135…
## $ VIVIENDAS   <dbl> 82, 365, 629, 375, 445, 744, 341, 505, 504, 546, 275, 895,…
## $ HOGARES     <dbl> 65, 116, 101, 136, 129, 314, 209, 275, 202, 347, 129, 342,…
## $ HOGARES_NBI <dbl> 19, 25, 1, 7, 16, 104, 110, 32, 49, 89, 15, 57, 1, 1, 2, 2…
## $ AREA_KM2    <dbl> 1.79899705, 0.01856469, 0.04438025, 0.36634000, 0.01836301…
## $ geometry    <MULTIPOLYGON [°]> MULTIPOLYGON (((-58.37189 -..., MULTIPOLYGON …

Una vez importado nuestro nuevo dataframe, el cual, como puede verse, es un dataframe de datos espaciales, seleccionamos nuestras variables de interés (población y área, medida en kilómetros cuadrados) y creamos a partir de una simple operación entre ambas, nuestra nueva variable densidad poblacional por radio censal:

densidad_poblacional <- radios_censales %>% 
                        mutate(densidad_poblacional=POBLACION/AREA_KM2) %>% 
                        select(densidad_poblacional, geometry)

2) Mapeando las mejores localizaciones

Una vez que ya contamos con todas nuestras variables de interés, procedemos a construir nuestro índice, que no es más que una variable compleja creada a partir del promedio ponderado de esas variables simples.

manzanasfinal <- cobertura_por_manzana_con_distancias %>% 
                 left_join(precio_promedio_por_manzana_completo, by="SM") %>% 
                 st_join(densidad_poblacional)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
manzanasfinal <- manzanasfinal %>% 
                 st_set_geometry(NULL) %>% 
                 group_by(SM) %>% 
                 summarise(densidad_poblacional=mean(densidad_poblacional)) %>% 
                 left_join(precio_promedio_por_manzana_completo, by="SM") %>% 
                 left_join(cobertura_por_manzana_con_distancias, by="SM")
quiebres <- c(0,0.2,0.4,0.6,0.8,1)
manzanasfinal_indice <- manzanasfinal%>%mutate(cat_densidad=cut(densidad_poblacional,breaks=quantile(densidad_poblacional,quiebres,na.rm=TRUE),include.lowest=TRUE),cat_precio=cut(-precio_promedio_ok,breaks=quantile(-precio_promedio_ok,quiebres,na.rm=TRUE),include.lowest=TRUE),cat_distancia_av=cut(-distancia_av_mas_cercana,breaks=quantile(-distancia_av_mas_cercana,quiebres,na.rm=TRUE),include.lowest=TRUE),cat_distancia_sub=cut(-distancia_estacion_mas_cercana,breaks=quantile(-distancia_estacion_mas_cercana,quiebres,na.rm=TRUE),include.lowest=TRUE))
manzanasfinal_indice <- manzanasfinal_indice %>%
                        mutate(cat_densidad=as.numeric(cat_densidad),
                               cat_precio=as.numeric(cat_precio),
                               cat_distancia_av=as.numeric(cat_distancia_av),
                               cat_distancia_sub=as.numeric(cat_distancia_sub),
                               cat_d=5,cat_c=0,cat_cobertura=ifelse(is.na(cobertura),cat_c,cat_d))
manzanasfinal_indice <- manzanasfinal_indice%>%mutate(I=cat_densidad*0.3+cat_precio*0.3+cat_distancia_av*0.1+cat_distancia_sub*0.1+cat_cobertura*0.2,I=ifelse(I>quantile(I,probs = 0.9,na.rm = TRUE),TRUE,FALSE))

En el mapa que se muestra a continuación pueden visualizarse las localizaciones óptimas para el emplazamiento de los centros de aislamiento según nuestro índice, en base a las variables seleccionadas. como puede observarse a simple vista el patron de distribución espacial de estas ubicaciones se solapa con la cobertura hospitalaria, así como con la zona céntrica de la ciudad, donde se registran mayores densidades de población y mayor accesibilidad en términos de transporte público, al mismo tiempo que se identifica cierto sesgo de la zona sur donde los alquileres resultan comparativamente más bajos.

ggplot() +
  geom_sf(data=barrios,color="white") +
  geom_sf(data=manzanasfinal_indice %>% 
               filter(!is.na(I)) ,aes(fill=I), color=NA) +
  scale_fill_manual(values = c(NA,"darkorchid4")) +
  guides(fill=FALSE) +
  theme_minimal() +
  coord_sf(datum=NA) +
  labs(title="Ubicaciones Óptimas centros de aislamiento COVID-19",
       caption="Fuente: elaboración propia en base a datos de GCBA y Properati")