Catálogo Nacional de Hospitales

Autor/a
Afiliación

Mariia Nilova

Universidad de Valencia

Fecha de publicación

1 de abril de 2026

Input

En la tarea 1 he obtenido un conjunto de datos oficial sobre hospitales (Catálogo Nacional de Hospitales). El fichero original incluye información administrativa (nombre, dirección, municipio, provincia, etc.), pero no siempre incluye coordenadas listas para mapear.

Descripción

Se detecta que el dataset oficial no está preparado como dataset espacial: faltan coordenadas, hay columnas con nombres complicados (espacios, puntos, acentos) y pueden aparecer duplicados o formatos distintos según el municipio/provincia. Por eso, antes de poder usarlo en mapas o análisis espacial, necesito hacer limpieza y normalización.

Tratamiento

  1. Leo fichero (Excel) y limpio nombres de columnas
#Cargamos los paquetes necesarios 

library(readxl)
library(dplyr)
library(sf)
library(leaflet)
library(tidyverse)

Voy a trabajar solo con la Comunitat Valenciana porque el archivo de toda España tiene más de 800 hospitales y sacar coordenadas para todos puede tardar mucho. Así lo hago más rápido y puedo revisar mejor los datos antes de ampliar al resto.

hosp <- read_excel("../data/2526020035/CNH_2025.xlsx")

# limpiar nombres de columnas, hacerles mas leibles para R 
names(hosp) <- make.names(names(hosp))

# ver columnas (para comprobar)
names(hosp)
 [1] "CCN"                   "CODCNH"                "Nombre.Centro"        
 [4] "Dirección"             "Teléfono"              "Cód..Municipio"       
 [7] "Municipio"             "Cód..Provincia"        "Provincia"            
[10] "Cód..CCAA"             "CCAA"                  "Código.Postal"        
[13] "CAMAS"                 "Cód..Clase.de.Centro"  "Clase.de.Centro"      
[16] "Cód..Dep..Funcional"   "Dependencia.Funcional" "Forma.parte.Complejo" 
[19] "CODIDCOM"              "Nombre.del.Complejo"   "ALTA"                 
[22] "Email"                
# filtro datos solo para Comunidad Valenciana
hosp_cv <- hosp %>%
  filter(Cód..CCAA %in% c("10"))
  1. Quito duplicados
# quito duplicados
hosp_sin_dups <- hosp_cv %>%
  distinct(CCN, CODCNH, .keep_all = TRUE)

nrow(hosp_cv )       # antes
[1] 64
nrow(hosp_sin_dups)  # después
[1] 64
# podemos comprobar que no tenemos duplicados
  1. Elimino columnas que no me sirven de momento

Elimino columnas que no sirven: en el fichero original hay variables con muchísimos valores vacíos (NA) o que no necesito para el objetivo del proyecto (por ejemplo datos de complejo o emails). Para simplificar el dataset y hacerlo más limpio, me quedo solo con las columnas que no tienen NAs.

library(dplyr)

na_por_columna <- colSums(is.na(hosp_sin_dups))
na_por_columna
                  CCN                CODCNH         Nombre.Centro 
                    0                     0                     0 
            Dirección              Teléfono        Cód..Municipio 
                    0                     0                     0 
            Municipio        Cód..Provincia             Provincia 
                    0                     0                     0 
            Cód..CCAA                  CCAA         Código.Postal 
                    0                     0                     0 
                CAMAS  Cód..Clase.de.Centro       Clase.de.Centro 
                    0                     0                     0 
  Cód..Dep..Funcional Dependencia.Funcional  Forma.parte.Complejo 
                    0                     0                     0 
             CODIDCOM   Nombre.del.Complejo                  ALTA 
                   64                    64                     0 
                Email 
                    3 
# podemos ver que hay muchos NAs en varias columnas: CODICOM, Nombre de complejo, Email. 
# Tal ves porque no eran obligatorias a rellenar 

hosp_reducido <- hosp_sin_dups %>%
  select(-CODIDCOM, -Nombre.del.Complejo, -Email)

names(hosp_reducido)
 [1] "CCN"                   "CODCNH"                "Nombre.Centro"        
 [4] "Dirección"             "Teléfono"              "Cód..Municipio"       
 [7] "Municipio"             "Cód..Provincia"        "Provincia"            
[10] "Cód..CCAA"             "CCAA"                  "Código.Postal"        
[13] "CAMAS"                 "Cód..Clase.de.Centro"  "Clase.de.Centro"      
[16] "Cód..Dep..Funcional"   "Dependencia.Funcional" "Forma.parte.Complejo" 
[19] "ALTA"                 
  1. Añado coordenadas (lat/lon)
# creo la direccion completa en una columna 
hosp_direcc <- hosp_reducido %>%
  mutate(DIRECCION_completa = paste0(Dirección, ", ", Municipio, ", ", Provincia))

# he elegido el metodo arcgis porque parece tener buenos resultados 
crds_arcgis <- tidygeocoder::geocode(hosp_direcc, address = DIRECCION_completa, method = "arcgis")
Passing 64 addresses to the ArcGIS single address geocoder
Query completed in: 35.8 seconds
crds_arcgis
# A tibble: 64 × 22
   CCN        CODCNH Nombre.Centro   Dirección Teléfono Cód..Municipio Municipio
   <chr>      <chr>  <chr>           <chr>     <chr>    <chr>          <chr>    
 1 1012000256 120148 Instituto de T… Avenida … 9642312… 120402         Castelló…
 2 1012000255 120159 Hospital Rey D… Calle Ma… 6397118… 120402         Castelló…
 3 1012000183 120043 Consorcio Hosp… Avenida … 9643543… 120402         Castelló…
 4 1012000182 120038 Hospital La Ma… Camino C… 9643568… 120402         Castelló…
 5 1012000180 120017 Hospital Gener… Avenida … 9647250… 120402         Castelló…
 6 1012000178 120136 Hospital Unive… Carreter… 9643997… 121359         Vila-real
 7 1012000288 120115 Hospital Comar… Avenida … 9644000… 121384         Vinaròs  
 8 1046000423 460351 Hospital Unive… Carreter… 9624581… 460174         Alzira   
 9 1046000629 460168 Hospital de Sa… Carreter… 9616990… 460706         Bétera   
10 1046008287 460404 IMED Valencia   Calle Fe… 9630030… 460787         Burjassot
# ℹ 54 more rows
# ℹ 15 more variables: Cód..Provincia <chr>, Provincia <chr>, Cód..CCAA <chr>,
#   CCAA <chr>, Código.Postal <chr>, CAMAS <chr>, Cód..Clase.de.Centro <chr>,
#   Clase.de.Centro <chr>, Cód..Dep..Funcional <chr>,
#   Dependencia.Funcional <chr>, Forma.parte.Complejo <chr>, ALTA <chr>,
#   DIRECCION_completa <chr>, lat <dbl>, long <dbl>
hosp_coor <- sf::st_as_sf(crds_arcgis , coords = c("long", "lat"), 
                       crs = 4326)
library(ggplot2)
GVA <- nominatimlite::geo_lite_sf("Comunidad Valenciana", points_only = FALSE)

GVA %>%
  ggplot() +
  geom_sf(data = GVA) +
  geom_sf(data = hosp_coor, alpha = 0.7, size = 1, col = "green") +
  labs(title = "Hospitales geocodificados (ArcGIS)", subtitle = "CRS: EPSG:4326")

Con el grafico se revisó visualmente que los puntos caen dentro de la Comunitat Valenciana, así que ArcGIS devuelve coordenadas y el mapa sale bien.

  1. Guardar output en CSV + GeoPackage
# CSV (sin geometría)
write_csv(st_drop_geometry(hosp_coor), "hospitales_cv_geocoded.csv")

# GeoPackage (con geometría)
st_write(hosp_coor, "hospitales_cv_geocoded.gpkg", layer = "hospitales_cv", delete_dsn = TRUE)
Deleting source `hospitales_cv_geocoded.gpkg' using driver `GPKG'
Writing layer `hospitales_cv' to data source 
  `hospitales_cv_geocoded.gpkg' using driver `GPKG'
Writing 64 features with 20 fields and geometry type Point.

Output

En este proyecto he trabajado con un fichero de hospitales y me he centrado en la Comunitat Valenciana para que el proceso fuese más manejable. Primero cargué el Excel y limpié los datos (nombres de columnas, duplicados y campos innecesarios). Después unifiqué la dirección en una sola columna y añadí coordenadas (latitud y longitud) mediante geocodificación para poder localizar cada centro en un mapa.

El resultado final se muestra en un mapa interactivo donde se pueden ver los hospitales y consultar su nombre y dirección.

Mapa interactivo

library(leaflet.extras)
hosp_coor %>%
  leaflet() %>% 
  addTiles() %>%
  addCircles(radius = 7,
             color = "green",
             label = ~Nombre.Centro, # pasar por encima y sale nombre 
             popup = ~Dirección) %>%
    leaflet.extras::addFullscreenControl() %>%
  leaflet.extras::addResetMapButton()

Los ficheros generados se pueden descargar de aquí.



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