Se ha extraído un conjunto de datos en formato xlsx
procedente del Portal
de Datos Abiertos de Castilla-La Mancha, plataforma oficial del
gobierno autonómico que proporciona acceso libre y gratuito a los datos
públicos generados por su administración. Contiene información
geoespacial oficial relacionada con las FARMACIAS
ADHERIDAS AL SESCAM PARA LA DISPENSACIÓN DE MATERIAL
ORTOPROTÉSICO en la provincia de Albacete.
A continuación, visualizamos en R la estructura de algunas de las observaciones incluidas en los datos que hemos descargado:
## Rows: 114
## Columns: 4
## $ POBLACIÓN <chr> "ALBACETE", "ALBACETE", "ALBACETE", "ALBACETE", "ALBACETE", …
## $ FARMACIA <chr> "ALMUDENA FERNANDEZ MARTINEZ", "JOSE V. GOMEZ DE QUEROCORDOB…
## $ DIRECCIÓN <chr> "C/ MARTINEZ VILLENA, 10", "AVDA. ESPAÑA, 21", "C/MAYOR, 16"…
## $ TELEFONO <chr> "967 21 60 13", "967 22 32 28", "967 24 56 71", "967 22 72 3…
El objetivo de este proyecto es la mejora, actualización y enriquecimiento espacial del dataset obtenido mediante un proceso de geocodificación así como la integración y contraste de otra fuente de datos de naturaleza colaborativa:
osmdata de R, se
extraerá la información correspondiente a la etiqueta
amenity=pharmacy dentro del bounding box de
Albacete a nivel provincial. Este conjunto aporta atributos dinámicos y
de gran interés público que no figuran en el registro oficial, como los
horarios de apertura (opening_hours), la accesibilidad para
sillas de ruedas (wheelchair) o la página web.A partir del análisis y exploración de las tres fuentes de datos mencionadas, se detectan las siguientes limitaciones y áreas de mejora:
Formato xlsx carente de geometría
espacial: El dataset oficial descargado del Sescam es un
archivo plano de hoja de cálculo (.xlsx). Aunque dispone de
columnas con información de ubicación, requiere un preprocesamiento para
convertir esas direcciones en coordenadas que permitan el análisis
espacial en R.
Déficit de atributos orientados al ciudadano: El registro oficial es de carácter estrictamente administrativo (código de autorización, titularidad, dirección postal). Se detecta una carencia total de variables de utilidad pública diaria, tales como disponibilidad, horarios o la accesibilidad del local.
Inconsistencia y valores nulos en la fuente colaborativa
(OSM): Al analizar los datos extraídos de OpenStreetMap para
suplir las carencias anteriores, se observa el sesgo típico de la
Información Geográfica Voluntaria (VGI). Número de variables extenso (30
variables) que presentan una alta tasa de valores faltantes
(NA) o falta de estandarización, requiriendo un proceso de
limpieza e imputación.
## Simple feature collection with 5 features and 3 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -0.9478393 ymin: 38.08169 xmax: -0.9403683 ymax: 38.08666
## Geodetic CRS: WGS 84
## name
## 488552961 Farmacia Ldo. Carlos Iniesta Penalva
## 496201233 Farmacia Lda. M.ª del Pino Salar Pomares - Ldo. Jorge Martos Marco
## 496201242 Farmacia Ldo. Manuel Franco Tomás
## 513731304 Farmacia Ldo. Gonzalo Chazarra Navarro
## 527990689 Farmacia Lda. Victoria Moreno
## wheelchair opening_hours geometry
## 488552961 <NA> <NA> POINT (-0.9456044 38.08169)
## 496201233 <NA> <NA> POINT (-0.946822 38.08454)
## 496201242 <NA> <NA> POINT (-0.9478393 38.08456)
## 513731304 <NA> <NA> POINT (-0.9426321 38.08222)
## 527990689 <NA> <NA> POINT (-0.9403683 38.08666)
Para poder llevar a cabo este proyecto, se ha utilizado RStudio como herramienta para cargar, limpiar, depurar y cruzar los diferentes conjuntos de datos que se han mencionado. Así, el primer paso ha sido leer los datos oficiales del portal de Castilla-La Mancha que queremos mejorar espacialmente:
# Cargo todas las librerías que voy a usar
library(osmdata)
library(sf)
library(mapSpain)
library(tidyverse)
library(readxl)
library(rio)
# --- Cargo los datos del portal de CLM ---
url_farmacias <- "https://datosabiertos.castillalamancha.es/sites/datosabiertos.castillalamancha.es/files/FARMACIAS%20ALBACETE.xlsx"
# Señalo skip = 1 para saltar el titulo que viene en el archivo .xlsx
farmacias_clm <- import(url_farmacias, skip = 1) %>%
# Elimino la primera fila de los datos (la que pone solo "Albacete" porque deja una fila solo con valores vacíos y no me interesa)
slice(-1)%>%
# Elimino las 3 últimas filas del dataset (anotaciones que no son de interés en el tratamiento de los datos)
head(-3)Una vez se han leído los datos oficiales que se pretenden contrastar y enriquecer, toca cargar datos de fuentes alternativas con información ampliada. Así, el segundo paso de esta fase de tratamiento será leer los datos de OSM.
# --- Cargo los datos de OSM ---
# 1. Obtengo el bounding box de la provincia de Albacete
alba_prov <- esp_get_prov("Albacete", epsg = "4326")
bbox_alba_prov <- st_bbox(alba_prov)
# 2. Se realiza la consulta a OSM para las farmacias de toda la provincia
q_farmacias_osm <- bbox_alba_prov %>%
opq(timeout = 3600) %>%
add_osm_feature(key = "amenity", value = "pharmacy")
# 3. Extraigo las geometrías de puntos
farmacias_osm_puntos <- osmdata_sf(q_farmacias_osm)$osm_pointsUna alternativa para lograr una menor carga computacional es
descargar los datos en la unidad local del equipo mediante la función
st_write una vez se hayan extraído de OSM. De esta forma
cada vez que sea necesario renderizar el código, no se realiza una
consulta a un servidor externo (OSM) ahorrando problemas de tiempo y
eficiencia. Simplemente se leen con la función st_read como
se muestra a continuación.
Tras su lectura, se inicia la fase de depuración de este conjunto colaborativo, filtrando exclusivamente los atributos de interés para la ciudadanía (como horarios y accesibilidad) y tratando los posibles valores nulos antes de su integración.
# 1. DEPURACIÓN DE OSM
farmacias_osm_limpio <- farmacias_osm_puntos %>%
# Nos quedamos con todas las variables de interés que enriquecerán el dataset oficial
select(osm_id, name, wheelchair, opening_hours, phone, website) %>%
# Estandarizamos los valores nulos en todas las nuevas variables simultáneamente
# para mantener la coherencia en el dataset final
mutate(across(c(wheelchair, opening_hours, phone, website),
~ifelse(is.na(.), "No consta", .)))Como ya se ha mencionado previamente, el conjunto de datos oficial
del Sescam carece de geometría espacial y de coordenadas explícitas,
ofreciendo únicamente la dirección postal de cada establecimiento. Para
poder integrarlo es clave realizar primero un proceso de geocodificación
que transforme estas direcciones en coordenadas (latitud y longitud).
Este proceso se lleva a cabo mediante el paquete
tidygeocoder. Posteriormente, los registros geocodificados
se transforman en un objeto espacial sf (EPSG:4326) para permitir el
cruce con otras fuentes de datos.
En esta fase del tratamiento se hace uso de la función
geocode(), similar a la función geo() vista en
clase pero más versátil cuando se trabaja con la dinámica de los pipes
(%>%) de la librería dplyr. Esta función
convierte direcciones postales en coordenadas reales, agregando al
dataset original dos columnas nuevas: lat y long. El
método que se especifica en la función es arcgis puesto que
completa el proceso de geocodificación sin devolver ningún valor vacío
(NA).
# Cargo la librería necesaria para geocodificar
library(tidygeocoder)
# 2. GEOCODIFICACIÓN Y ESPACIALIZACIÓN DEL DATASET OFICIAL (CLM)
farmacias_clm_geo <- farmacias_clm %>%
# Creo una dirección completa para ayudar al buscador a no equivocarse de ciudad
mutate(direccion_completa = paste(DIRECCIÓN, ", Albacete, España", sep = "")) %>%
# Geocodificación
geocode(address = direccion_completa, method = 'arcgis', lat = latitud, long = longitud)
# Me aseguro de que no hay valores vacíos
sum(is.na(farmacias_clm_geo))## [1] 0
Seguidamente, los registros geocodificados se transforman en un objeto espacial sf (EPSG:4326) para permitir el cruce con otras fuentes de datos.
Una vez que ambos conjuntos de datos disponen de geometrías nativas y
comparten el mismo Sistema de Referencia de Coordenadas (EPSG:4326), se
procede a su integración topológica. Dado que las coordenadas calculadas
mediante geocodificación y las registradas por los colaboradores de OSM
rara vez coinciden con exactitud milimétrica, se aplica un cruce
espacial basado en el criterio geométrico del vecino más cercano
(st_nearest_feature). Este paso constituye el núcleo del
enriquecimiento de los datos, ya que transfiere los atributos dinámicos
de OSM (horarios, teléfono, sitio web y nivel de accesibilidad) a la
farmacia oficial correspondiente del Sescam.
# 3. CRUCE ESPACIAL (SPATIAL JOIN)
# Enriquecemos el dataset oficial vinculando cada farmacia con la más cercana en OSM
farmacias_unidas <- st_join(
farmacias_clm_sf,
farmacias_osm_limpio,
join = st_nearest_feature
)
# Guardo el resultado final
# En formato .gpkg
st_write(farmacias_unidas, "farmacias_enriquecidas.gpkg", append = FALSE, quiet = TRUE)
# En formato .xlsx
farmacias_unidas %>%
sf::st_drop_geometry() %>%
export("farmacias_enriquecidas.xlsx")Se ha obtenido un conjunto de datos espaciales enriquecido que integra de forma exitosa el directorio oficial de farmacias del Sescam con la información colaborativa ciudadana de OpenStreetMap. Este nuevo dataset definitivo ha superado las limitaciones del dataset original, adquiriendo geometrías nativas (EPSG:4326) mediante geocodificación. Además, ha sido dotado de variables de alto interés público (horarios de apertura, accesibilidad para personas con movilidad reducida y datos de contacto), resolviendo las carencias del registro puramente administrativo inicial y generando una herramienta de mayor valor para la ciudadanía.
El fichero generado con este procedimiento se puede descargar:
A continuación, se presenta un visor interactivo donde se puede explorar el resultado final de la integración espacial. Haciendo clic sobre cada marcador, es posible consultar los atributos dinámicos heredados de OpenStreetMap para cada farmacia oficial.
library(leaflet)
leaflet(data = farmacias_unidas) %>%
# Añadimos un mapa base claro y elegante
addProviderTiles(providers$CartoDB.Positron) %>%
# Añadimos los marcadores con agrupamiento (clusters) y popups personalizados
addMarkers(
clusterOptions = markerClusterOptions(),
popup = ~paste0(
"<b>Farmacia: </b>", FARMACIA, "<br>",
"<b>Dirección: </b>", DIRECCIÓN, "<br>",
"<hr>",
"<i>Accesibilidad: </i>", wheelchair, "<br>",
"<i>Horario: </i>", opening_hours, "<br>",
"<i>Teléfono: </i>", phone
)
)

Proyecto de Innovación Educativa Emergente (PIEE-2737007)