library(dplyr)
library(tidyverse)
library(sf)
library(mapSpain)
library(osmdata)
#ESPAÑA
spain <- mapSpain::esp_get_country(moveCAN = F)
bbox_spain <- c(-10, 35, 5, 45)
q211 <- bbox_spain %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "kindergarten")
guardesp <- osmdata_sf(q211)
guardesp_points <- guardesp$osm_points
guardesp_points <- st_transform(guardesp_points, st_crs(spain)) #Transformamos el conjunto de coordenadas al mismo #sistema que las utilizadas en Spain
guardesp_points <- st_intersection(guardesp_points, spain) #Escogemos únicamente aquellas coordenadas que #pertenezcan a España, es decir la intersección de las dos geometrias.
q212 <- bbox_spain %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "school")
escesp <- osmdata_sf(q212)
escesp_points <- escesp$osm_points
escesp_points <- st_transform(escesp_points, st_crs(spain))
escesp_points <- st_intersection(escesp_points, spain)
q213 <- bbox_spain %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "university")
uniesp <- osmdata_sf(q213)
uniesp_points <- uniesp$osm_points
uniesp_points <- st_transform(uniesp_points, st_crs(spain))
uniesp_points <- st_intersection(uniesp_points, spain)
# COMUNIDAD VALENCIANA
cvalenciana <- mapSpain::esp_get_ccaa() %>% filter(codauto == 10)
bbox_cval <- sf::st_bbox(cvalenciana)
q221 <- bbox_cval %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "kindergarten")
guardcval <- osmdata_sf(q221)
guardcval_points <- guardcval$osm_points
guardcval_points <- st_transform(guardcval_points, st_crs(cvalenciana))
guardcval_points <- st_intersection(guardcval_points, cvalenciana)
q222 <- bbox_cval %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "school")
esccval <- osmdata_sf(q222)
esccval_points <- esccval$osm_points
esccval_points <- st_transform(esccval_points, st_crs(cvalenciana))
esccval_points <- st_intersection(esccval_points, cvalenciana)
q223 <- bbox_cval %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "university")
unicval <- osmdata_sf(q223)
unicval_points <- unicval$osm_points
unicval_points <- st_transform(unicval_points, st_crs(cvalenciana))
unicval_points <- st_intersection(unicval_points, cvalenciana)
# VALENCIA (PROVINCIA)
val <- mapSpain::esp_get_prov() %>% filter(cpro == "46")
bbox_valp <- sf::st_bbox(val)
q231 <- bbox_valp %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "kindergarten")
guardvalp <- osmdata_sf(q231)
guardvalp_points <- guardvalp$osm_points
guardvalp_points <- st_transform(guardvalp_points, st_crs(val))
guardvalp_points <- st_intersection(guardvalp_points, val)
q232 <- bbox_valp %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "school")
escvalp <- osmdata_sf(q232)
escvalp_points <- escvalp$osm_points
escvalp_points <- st_transform(escvalp_points, st_crs(val))
escvalp_points <- st_intersection(escvalp_points, val)
q233 <- bbox_valp %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "university")
univalp <- osmdata_sf(q233)
univalp_points <- univalp$osm_points
univalp_points <- st_transform(univalp_points, st_crs(val))
univalp_points <- st_intersection(univalp_points, val)
# VALENCIA
valencia <- mapSpain::esp_get_munic() %>% filter(name == "Valencia")
bbox_valencia <- sf::st_bbox(valencia)
q241 <- bbox_valencia %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "kindergarten")
guardvalencia <- osmdata_sf(q241)
guardvalencia_points <- guardvalencia$osm_points
guardvalencia_points <- st_transform(guardvalencia_points, st_crs(valencia))
guardvalencia_points <- st_intersection(guardvalencia_points, valencia)
q242 <- bbox_valencia %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "school")
escvalencia <- osmdata_sf(q242)
escvalencia_points <- escvalencia$osm_points
escvalencia_points <- st_transform(escvalencia_points, st_crs(valencia))
escvalencia_points <- st_intersection(escvalencia_points, valencia)
q243 <- bbox_valencia %>%
osmdata::opq(timeout = 3600) %>%
osmdata::add_osm_feature(key = "amenity", value = "university")
univalencia <- osmdata_sf(q243)
univalencia_points <- univalencia$osm_points
univalencia_points <- st_transform(univalencia_points, st_crs(valencia))
univalencia_points <- st_intersection(univalencia_points, valencia)
Datos sobre educación
Input
Se han obtenido tres conjuntos de datos para cuatro niveles geográficos diferentes. Estas bases de datos tienen una temática en común, se trata de centros educativos, más concretamente se ha obtenido información sobre guarderías, colegios y universidades en España, la Comunidad Valenciana, la provincia de Valencia y el municipio de Valencia.
Estos conjuntos de datos se han obtenido utilizando OpenStreetMap. OSM es un proyecto colaborativo para crear un mapa libre y editable del mundo, el cual permite a los usuarios visualizar, editar y utilizar datos geográficos de cualquier parte del globo.Los datos procedentes de este proyecto son recopilados por personas voluntarias, por lo que es posible que para un mismo tipo de dato no tengamos las mismas características.
Para mejorar los datos obtenidos, podemos realizar diferentes modificaciones. Por una parte, podemos unificar las bases de datos que pertenecen a la misma zona geográfica, y añadir una columna que nos indique si se trata de una guardería, un colegio o una universidad. Por otra parte, como los datos son extraidos de un proyecto voluntario, podemos encontrarnos con diferentes problemas como pueden ser los datos duplicados, los datos incompletos o incluso que no hayamos obtenido todos los datos, debido a interferencias en la clasificación de los datos.
Descripción
Se detecta que los datos obtenidos proporcionan muchas variables con datos vacíos, esto se debe a que los datos han sido extraidos de una web en la que los usuarios introducen los datos voluntariamente, y pueden decidir no ser tan rigurosos con la información como otros lo han sido. También encontramos un elevado número de variables en nuestros conjuntos de datos, y en muchas ocasiones estas no nos proporcionan prácticamente información, por lo que se podría prescindir de ellas.
Tratamiento
En primer lugar, vamos a unificar las bases de datos para la misma zona geográfica en una sola, y para ello, primero crearemos una variable que nos indique para cada observación si se trata de una guardería, de un colegio o de una universidad.
#Unificación zona geográfica ESPAÑA
## Agregamos columna tipo centro
guardesp_points <- guardesp_points %>%
mutate(tipo = "Guardería")
escesp_points <- escesp_points %>%
mutate(tipo = "Colegio")
uniesp_points <- uniesp_points %>%
mutate(tipo = "Universidad")
## Unimos las bases de datos
espanya_edu <- bind_rows(guardesp_points, escesp_points, uniesp_points)
#Unificación zona geográfica COMUNIDAD VALENCIANA
## Agregamos columna tipo centro
guardcval_points <- guardcval_points %>%
mutate(tipo = "Guardería")
esccval_points <- esccval_points %>%
mutate(tipo = "Colegio")
unicval_points <- unicval_points %>%
mutate(tipo = "Universidad")
## Unimos las bases de datos
comunidadvalenciana_edu <- bind_rows(guardcval_points, esccval_points, unicval_points)
#Unificación zona geográfica provincia de VALENCIA
## Agregamos columna tipo centro
guardvalp_points <- guardvalp_points %>%
mutate(tipo = "Guardería")
escvalp_points <- escvalp_points %>%
mutate(tipo = "Colegio")
univalp_points <- univalp_points %>%
mutate(tipo = "Universidad")
## Unimos las bases de datos
provvalencia_edu <- bind_rows(guardvalp_points, escvalp_points, univalp_points)
#Unificación zona geográfica municipio de VALENCIA
## Agregamos columna tipo centro
guardvalencia_points <- guardvalencia_points %>%
mutate(tipo = "Guardería")
escvalencia_points <- escvalencia_points %>%
mutate(tipo = "Colegio")
univalencia_points <- univalencia_points %>%
mutate(tipo = "Universidad")
## Unimos las bases de datos
valencia_edu <- bind_rows(guardvalencia_points, escvalencia_points, univalencia_points)
El siguiente paso a realizar es comprobar si hay duplicados. Al tratarse de datos espaciales, existen ocasiones en los que no podamos detectar datos duplicados, debido a que un mismo dato puede haberse registrado con diferentes coordenadas, pero dentro de lo posible vamos a intentar deshacernos de ellos.
num_duplicados <- sum(duplicated(espanya_edu))
# Mostrar el número de duplicados
print(paste("Número de filas duplicadas:", num_duplicados))
Podemos suponer que si no hay duplicados en la base de datos de España, tampoco encontraremos en las otras, pero esto no demuestra realmente que no existen duplicados, si no que es posible que ocurra lo que nos temiamos, un mismo lugar ha sido añadido con diferentes puntos de coordenadas.
Para intentar solucionar este problema, vamos a utilizar una estrategia basada en el clustering, y para ello vamos a coger una distancia máxima de 50 metros.
library(dbscan)
espanya_edu <- st_transform(espanya_edu, 25830) # EPSG:25830 (ETRS89 / UTM zone 30N)
# Extraemos coordenadas de la geometría
coords <- st_coordinates(espanya_edu)
# Aplicamos clustering DBSCAN teniendo en cuenta el tipo (por separado para cada grupo)
espanya_clustered <- espanya_edu %>%
group_by(tipo) %>% # Agrupar por tipo (Guardería, Colegio, Universidad)
mutate(
cluster = {
# Extraer las coordenadas del grupo actual
coords_group <- coords[which(espanya_edu$tipo == tipo), ]
# Aplicamos DBSCAN para el grupo específico
result <- dbscan(coords_group, eps = 50, minPts = 1)
# Asignar los clusters a la columna "cluster" según el grupo
result$cluster
}
) %>%
ungroup()
# Añadimos la asignación de cluster al dataset
espanya_edu_uni <- espanya_clustered %>%
group_by(tipo, cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
# Unificamos puntos dentro del mismo cluster (puedes usar el centroide)
espanya_edu_unif <- espanya_clustered %>%
group_by(cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
comunidadvalenciana_edu <- st_transform(comunidadvalenciana_edu, 25830) # EPSG:25830 (ETRS89 / UTM zone 30N)
# Extraemos coordenadas de la geometría
coords <- st_coordinates(comunidadvalenciana_edu)
# Aplicamos clustering DBSCAN teniendo en cuenta el tipo (por separado para cada grupo)
cvalenciana_clustered <- comunidadvalenciana_edu %>%
group_by(tipo) %>% # Agrupar por tipo (Guardería, Colegio, Universidad)
mutate(
cluster = {
# Extraer las coordenadas del grupo actual
coords_group <- coords[which(comunidadvalenciana_edu$tipo == tipo), ]
# Aplicamos DBSCAN para el grupo específico
result <- dbscan(coords_group, eps = 50, minPts = 1)
# Asignar los clusters a la columna "cluster" según el grupo
result$cluster
}
) %>%
ungroup()
# Añadimos la asignación de cluster al dataset
comunidadvalenciana_edu_unif <- cvalenciana_clustered %>%
group_by(tipo, cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
# Unificamos puntos dentro del mismo cluster (puedes usar el centroide)
comunidadvalenciana_edu_unif <- cvalenciana_clustered %>%
group_by(cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
provvalencia_edu <- st_transform(provvalencia_edu, 25830) # EPSG:25830 (ETRS89 / UTM zone 30N)
# Extraemos coordenadas de la geometría
coords <- st_coordinates(provvalencia_edu)
# Aplicamos clustering DBSCAN teniendo en cuenta el tipo (por separado para cada grupo)
provvalencia_clustered <- provvalencia_edu %>%
group_by(tipo) %>% # Agrupar por tipo (Guardería, Colegio, Universidad)
mutate(
cluster = {
# Extraer las coordenadas del grupo actual
coords_group <- coords[which(provvalencia_edu$tipo == tipo), ]
# Aplicamos DBSCAN para el grupo específico
result <- dbscan(coords_group, eps = 50, minPts = 1)
# Asignar los clusters a la columna "cluster" según el grupo
result$cluster
}
) %>%
ungroup()
# Añadimos la asignación de cluster al dataset
provvalencia_edu_uni <- provvalencia_clustered %>%
group_by(tipo, cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
# Unificamos puntos dentro del mismo cluster (puedes usar el centroide)
provvalencua_edu_unif <- provvalencia_clustered %>%
group_by(cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
valencia_edu <- st_transform(valencia_edu, 25830) # EPSG:25830 (ETRS89 / UTM zone 30N)
# Extraemos coordenadas de la geometría
coords <- st_coordinates(valencia_edu)
# Aplicamos clustering DBSCAN teniendo en cuenta el tipo (por separado para cada grupo)
valencia_clustered <- valencia_edu %>%
group_by(tipo) %>% # Agrupar por tipo (Guardería, Colegio, Universidad)
mutate(
cluster = {
# Extraer las coordenadas del grupo actual
coords_group <- coords[which(valencia_edu$tipo == tipo), ]
# Aplicamos DBSCAN para el grupo específico
result <- dbscan(coords_group, eps = 50, minPts = 1)
# Asignar los clusters a la columna "cluster" según el grupo
result$cluster
}
) %>%
ungroup()
# Añadimos la asignación de cluster al dataset
valencia_edu_uni <- valencia_clustered %>%
group_by(tipo, cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
# Unificamos puntos dentro del mismo cluster (puedes usar el centroide)
valencia_edu_unif <- valencia_clustered %>%
group_by(cluster) %>%
summarise(geometry = st_centroid(st_union(geometry)), .groups = "drop")
Output
Se han obtenido cuatro conjuntos de datos que nos aportan información sobre la educación. Concretamente, hemos obtenido un conjunto de datos para España, otro para la Comunidad Valenciana, otro para la provincia de Valencia y otro para el municipio de Valencia. Estos conjuntos de datos nos aportan información sobre guarderías, colegios y universidades, identificando cuales son dentro de la variable tipo.
# Crear la carpeta _files/gpkg si no existe
output_dir <- "_files/gpkg"
if (!dir.exists(output_dir)) dir.create(output_dir, recursive = TRUE)
# Definir el archivo de salida
archivo_salida <- file.path(output_dir, "edu.gpkg")
# Si el archivo ya existe, eliminarlo antes de escribir
if (file.exists(archivo_salida)) file.remove(archivo_salida)
# Función para escribir cada capa si los datos existen
guardar_capa <- function(datos, nombre) {
if (exists(deparse(substitute(datos))) && !is.null(datos) && nrow(datos) > 0) {
st_write(datos, archivo_salida, layer = nombre, append = TRUE)
} else {
message(paste("Aviso: No se guardó la capa", nombre, "porque está vacía o no existe."))
}
}
# Guardar cada conjunto de datos
guardar_capa(espanya_edu_unif, "Espanya")
guardar_capa(comunidadvalenciana_edu_unif, "CValenciana")
guardar_capa(provvalencia_edu_unif, "ProvValencia")
guardar_capa(valencia_edu_unif, "Valencia")
El fichero generado con este procedimiento se puede descargar de aquí. Este archivo contiene diferentes capas, una para cada nivel geográfico.
Proyectos de Innovación Educativa Emergente PIEE-2737007 y PIEE-3325394