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…
Enriquecimiento Espacial del Directorio de Farmacias en Albacete
Input
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:
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:
-
Conjunto de datos de contraste: OpenStreetMap (OSM). Mediante el paquete
osmdatade R, se extraerá la información correspondiente a la etiquetaamenity=pharmacydentro 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.
Descripción
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
xlsxcarente 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)
Tratamiento
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)Datos de OpenStreetMap
Lectura
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.
farmacias_osm_puntos <- st_read("farmacias_osm_albacete.gpkg")Depuració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", .)))Espacialización del dataset original
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.
Cruce Espacial (OSM + Portal CLM)
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")Output
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.
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
)
)El/los fichero(s) generados con este procedimiento/técnica/metodología se puede(n) descargar de aquí.

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