# Paquetes a utilizar
library(readr)
library(dplyr)
library(purrr)
library(sf)
library(mapview)
library(osrm)
library(ggplot2)
library(patchwork)
Estimar tiempos de viaje a servicios esenciales, como insumo para estadísticas que fundamenten programas de urbanización de asentamientos precarios en la ciudad de Montevideo.
Establecimientos educativos: Oferta educativa de la ANEP, Catálogo Nacional de Datos Abiertos de la Agencia de Gobierno Electrónico y Sociedad de la Información y del Conocimiento (AGESIC) de la ROU.
Establecimientos de salud pública: Sistema de Información Geográfica de la Administración Nacional de Educación Pública (ANEPO) de la ROU.
Polígonos delimitando asentamientos precarios: Portal de Datos Abiertos, Intendencia de Montevideo.
asentamientos <- read_sf("~/Downloads/MVD/v_ai_asentamientos_publicables/v_ai_asentamientos_publicables.shp") |> group_by(CODIGOINE, NOMBRE, ESTADODESC) |>
summarise() |>
st_transform(4326) |>
st_make_valid()
educacion <- read_sf("~/Downloads/MVD/ceip/CEIP.shp") |>
filter(Departamen == "MONTEVIDEO")|>
rename(id = OBJECTID) |>
st_transform(4326)
salud <- mutate(read_sf("~/Downloads/MVD/Centros_de_salud_UY/Centros_de_salud_UY.shp"),
tipo = "Centro de salud") |>
rbind(mutate(read_sf("~/Downloads/MVD/Policlinicas/Policlinicas.shp"),
tipo = "Policlínica")) |>
rbind(mutate(read_sf("~/Downloads/MVD/Hospitales_UY/Hospitales_UY.shp"),
tipo = "Hospital"))|>
filter(departamen == "MONTEVIDEO") |>
st_transform(4326)
Los datos oficiales consideran la existencia de 348 asentamientos irregulares en la ciudad, con cinco categorías de intervención:
mapview(summarise(group_by(asentamientos, ESTADODESC)),
layer.name = "Status")
Todos los asentamientos serán considerados para el análisis.
En Uruguay, la diferencia principal entre los tipos de establecimiento de salud pública es el nivel de complejidad y los servicios ofrecidos: una policlínica brinda atención ambulatoria y primaria, un centro de salud integra policlínicas y servicios de prevención con atención primaria, y un hospital es un centro de mayor complejidad con internación, urgencias, cirugías y tratamientos especializados.
mapview(list(st_union(asentamientos), select(salud, tipo)),
layer.name = c("Asentamientos precarios", "Establecimientos de Salud Pública"))
Para el análisis consideraremos Hospitales y Centros de Salud, ya que son los establecimientos que brindan servicios de salud preventiva.
salud <- salud |>
filter(tipo %in% c("Hospital", "Centro de salud"))
mapview(list(st_union(asentamientos), select(educacion, Tipo_de_Ed)),
layer.name = c("Asentamientos precarios", "Establecimientos de Educación Pública"))
Para el análisis consideraremos establecimientos de educación primaria común.
educacion <- educacion |>
filter(Tipo_de_Ed == "ESCUELAS COMUNES")
Estimaremos la distancia ente asentamientos y puntos de servicio con los siguientes parámetros:
Para la estimación de tiempo y distancia de viajes se utilizará OSRM (Open Source Routing Machine), un sistema de ruteo de código abierto que calcula rutas óptimas utilizando como referencia las calles georreferenciadas en la base de datos libre OpenStreetMap (OSM).
## Preparativos
# El ruteo requiere de una instancia local de OSRM
# véase:
# https://rpubs.com/HAVB/osrm
# IMPORTANTE configurar osrm para rutas a pie ("foot"),
# en la sección "Preprocesar los datos de ruteo" del tutorial
options(osrm.server = "http://127.0.0.1:5000/")
# Función auxiliar para encontrar el establecimiento más cercano a cada origen
obtener_df_viajes <- function(origins, destinations) {
origins <- sf::st_centroid(origins)
destinations <- sf::st_centroid(destinations)
id_closest <- unlist(nngeo::st_nn(origins, destinations))
# Return routing ready dataframe
data.frame(
orig_id = origins[["CODIGOINE"]],
orig_X = st_coordinates(origins)[, 1],
orig_Y = st_coordinates(origins)[, 2],
dest_id = destinations[id_closest, ][["id"]],
dest_X = st_coordinates(destinations[id_closest, ])[, 1],
dest_Y = st_coordinates(destinations[id_closest, ])[, 2],
stringsAsFactors = FALSE
)
}
viajes_educacion <- obtener_df_viajes(asentamientos, educacion)
viajes_salud <- obtener_df_viajes(asentamientos, salud)
Como ejemplo, calculamos y mostramos uno de los viajes desde asentamiento hasta hospital o centro de salud más cercano:
viaje <- osrmRoute(src = c(viajes_salud[1,]$orig_X, viajes_salud[1,]$orig_Y),
dst = c(viajes_salud[1,]$dest_X, viajes_salud[1,]$dest_Y),
overview = "full")
mapview(viaje)
Resolvemos todos los viajes
get_routes <- function(trips_df) {
get_route <- purrr::possibly(
function(orig_id, orig_X, orig_Y, dest_id, dest_X, dest_Y) {
route <- osrm::osrmRoute(src = c(orig_X, orig_Y),
dst = c(dest_X, dest_Y),
overview = FALSE)
data.frame(orig_id,
dest_id,
duration = route["duration"],
distance = route["distance"],
stringsAsFactors = FALSE)
},
otherwise = NULL)
purrr::pmap_df(trips_df, get_route)
}
rutas_educacion <- get_routes(trips_df = viajes_educacion)
rutas_salud <- get_routes(trips_df = viajes_salud)
# Distancia recorrida
# Educación
p1 <- ggplot(rutas_educacion, aes(x = distance)) +
geom_histogram(color = "white", fill = "salmon",
bins = 30,
alpha = 0.7) +
scale_x_continuous(breaks = seq(0, ceiling(max(rutas_educacion$distance)), 1)) +
theme_minimal(base_size = 14) +
labs(title = "Distribución de distancias de viaje\n", subtitle = "a educación pública (primaria)", x = "km", y = "casos")
# Salud
p2 <- ggplot(rutas_salud, aes(x = distance)) +
geom_histogram(color = "white", fill = "lightblue",
bins = 30,
alpha = 0.7) +
scale_x_continuous(breaks = seq(0, ceiling(max(rutas_salud$distance)), 1)) +
theme_minimal(base_size = 14) +
labs(subtitle = "a salud pública (hospitales y centros de salud)", x = "km", y = "casos")
# Combinar
p1 / p2
# Tiempo de viaje
# Educación
p1 <- ggplot(rutas_educacion, aes(x = duration)) +
geom_histogram(color = "white", fill = "salmon",
bins = 30,
alpha = 0.7) +
scale_x_continuous(breaks = seq(0, ceiling(max(rutas_educacion$duration)), 10)) +
theme_minimal(base_size = 14) +
labs(title = "Distribución de tiempos de viaje\n", subtitle = "a educación pública (primaria)",
x = "minutos", y = "casos")
# Salud
p2 <- ggplot(rutas_salud, aes(x = duration)) +
geom_histogram(color = "white", fill = "lightblue",
bins = 30,
alpha = 0.7) +
scale_x_continuous(breaks = seq(0, ceiling(max(rutas_salud$duration)), 10)) +
theme_minimal(base_size = 14) +
labs(subtitle = "a salud pública (hospitales y centros de salud)", x = "minutos", y = "casos")
# Combinar
p1 / p2
mean(rutas_educacion$distance > 2)
## [1] 0.08045977
mean(rutas_salud$duration > 60)
## [1] 0.1293103