libs <- c("readxl", "writexl", "rvest", "xml2", "tidyverse", "openxlsx", "sf", "dplyr", "mapSpain", "ggplot2", "tidygeocoder", "leaflet", "knitr")
installed_libs <- libs %in% rownames(installed.packages())
if (any(installed_libs == F)) {install.packages(libs[!installed_libs])}
invisible(lapply(libs, library, character.only = T))
rm(libs, installed_libs)
Municipios natales de todos los futbolistas españoles del Valencia Club de Fútbol
Input
Este proyecto busca representar gráficamente en un mapa interactivo, todos los municipios de España de los que provienen todos los jugadores nacionales que han debutado en partido oficial de cualquier competición con el Valencia CF, desde el día de su fundación, 18 de marzo de 1919, hasta el momento de realización de este trabajo, 10 de marzo de 2025.
No podemos empezar sin mencionar el inmenso trabajo de “Ciberche”, la mayor base de datos dedicada al Valencia CF y la página de donde hemos extraído toda la información, y agradecer su colaboración en este trabajo, facilitándonos dichos datos. El enlace a dicha página se adjunta aquí.
El trabajo ha sido realizado íntegramente a través del programa R.
Otra información de interés (metadatos):
Temática: Valencia CF
Autor: Ciberche
Fecha de extracción: 10 de marzo de 2025
Sitio web: https://www.ciberche.net/
Condiciones: “La presente base de datos está inscrita en el Registro de la Propiedad Intelectual con el número de asiento registral 09/2022/1276. Todos los datos recogidos son propiedad de Ciberche y su uso debe ser autorizado previamente por el propietario de los mismos.”
Descripción
Podemos empezar con la descripción de la base de datos obtenida, no sin antes cargar las librerías necesarias:
Una vez llevado a cabo este paso inicial, podemos cargar nuestra base de datos y echarle un primer vistazo.
players_VCF <- read.xlsx("data/000119/JUGADORES VCF (Ciberche).xlsx")
players_VCF <- players_VCF %>% filter("Min." > 0)
kable(head(players_VCF))
X1 | Nombre | Min | PJ | Tit | Sup | Cam | NJ | PG | %PG | PE | %PE | PP | %PP |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Aarón Ñíguez | 52 | 3 | 1 | 2 | 1 | 101 | 2 | 0.67 | 0 | 0.00 | 1 | 0.33 |
2 | Abdón García | 7380 | 82 | 82 | 0 | 0 | 60 | 34 | 0.41 | 14 | 0.17 | 34 | 0.41 |
3 | Abel Hernández | 0 | 0 | 0 | 0 | 0 | 36 | 0 | 0.00 | 0 | 0.00 | 0 | 0.00 |
4 | Abelardo González | 15176 | 171 | 167 | 4 | 3 | 242 | 86 | 0.50 | 38 | 0.22 | 47 | 0.27 |
5 | Adjutorio Serrat | 6886 | 80 | 79 | 1 | 6 | 56 | 27 | 0.34 | 25 | 0.31 | 28 | 0.35 |
6 | Adri Gómez | 0 | 0 | 0 | 0 | 0 | 46 | 0 | 0.00 | 0 | 0.00 | 0 | 0.00 |
Con estas dos líneas de código, hemos cargado los nombres y estadísticas (partidos jugados, minutos, porcentaje de victorias, etc.) de los casi mil jugadores españoles del Valencia CF que han sido convocados en partido oficial, y luego filtrado a aquellos cuya cantidad de minutos sea superior a cero, indicando así su debut con el equipo.
Como podemos ver, no existen datos geoespaciales de ningún tipo en nuestra base de datos, por lo que tuvimos que extraer esta base de datos a un excel (mostraremos el código en tipo comentario evitando así su ejecución, ya que no nos interesa guardar este archivo) y tras un tedioso proceso manual en el que copiamos de la base de datos de Ciberche todos los diferentes municipios natales de los 604 jugadores que aparecen ahora en el dataset, conseguimos añadir una variable más a nuestros datos y lo guardamos en un objeto diferente, eliminando aquellos sujetos que no nos interesaban, es decir, los que habíamos filtrados previamente:
# Extraemos la base de datos a un nuevo excel y añadimos manualmente las localidades
write_xlsx(players_VCF, "JUGADORES VCF.xlsx")
# Una vez añadida la nueva columna, cargamos el nuevo archivo
playersVCF <- read.xlsx("data/000119/JUGADORES VCF.xlsx")
kable(head(playersVCF))
X1 | Nombre | Min | PJ | Tit | Sup | Cam | NJ | PG | %PG | PE | %PE | PP | %PP | Localidad |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Aarón Ñíguez | 52 | 3 | 1 | 2 | 1 | 101 | 2 | 0.67 | 0 | 0.00 | 1 | 0.33 | Elche (Alicante) |
2 | Abdón García | 7380 | 82 | 82 | 0 | 0 | 60 | 34 | 0.41 | 14 | 0.17 | 34 | 0.41 | Avilés (Asturias) |
4 | Abelardo González | 15176 | 171 | 167 | 4 | 3 | 242 | 86 | 0.50 | 38 | 0.22 | 47 | 0.27 | Sotrondio (Asturias) |
5 | Adjutorio Serrat | 6886 | 80 | 79 | 1 | 6 | 56 | 27 | 0.34 | 25 | 0.31 | 28 | 0.35 | Olot (Girona) |
7 | Adrián Guerrero | 127 | 2 | 1 | 1 | 1 | 48 | 1 | 0.50 | 1 | 0.50 | 0 | 0.00 | Blanes (Girona) |
9 | Alba | 90 | 1 | 1 | 0 | 0 | 70 | 0 | 0.00 | 0 | 0.00 | 1 | 1.00 | NA |
Por tanto, para aclarar un poco toda esta parte que puede parecer un poco liosa, el proceso fue el siguiente: Obtuvimos el primer conjunto de datos con 964 jugadores (players_VCF) y filtramos aquellos que nos interesaban reduciendo en más de 300 observaciones el dataset. Luego guardamos este nuevo dataset (playersVCF) y le añadimos una variable nueva que eran las respectivas localidades. Hemos preferido guardarlo en estos dos objetos para diferenciarlos y por tanto, en este desarrollo, sólo necesitaremos el segundo, ya limpio y preparado para su manipulación.
Ahora sí, con nuestro conjunto de datos listo, podíamos empezar con su tratamiento.
Tratamiento
Primero de todo, podemos ver como la localidad aparecía conjunta, por lo que era importante separar el municipio de su provincia (y eliminar sus paréntesis), permitiéndonos así poder asignar una ubicación a cada municipio concreto, además de poder disponer de las respectivas provincias en caso de querer usarlas más tarde. Para ello, usamos estas líneas de código:
Ahora ya sí, podemos geolocalizar dichos municipios usando como referencia sus respectivos nombres con el paquete tidygeocoder a través de los datos de Open Street Maps (OSM). Esto nos llevará un rato, no más de 5 minutos.
playersVCF <- playersVCF %>%
geocode(address = "Ciudad", method = "osm")
Passing 247 addresses to the Nominatim single address geocoder
Query completed in: 251.2 seconds
kable(head(playersVCF))
X1 | Nombre | Min | PJ | Tit | Sup | Cam | NJ | PG | %PG | PE | %PE | PP | %PP | Ciudad | Provincia | lat | long |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Aarón Ñíguez | 52 | 3 | 1 | 2 | 1 | 101 | 2 | 0.67 | 0 | 0.00 | 1 | 0.33 | Elche | Alicante | 38.26533 | -0.6988391 |
2 | Abdón García | 7380 | 82 | 82 | 0 | 0 | 60 | 34 | 0.41 | 14 | 0.17 | 34 | 0.41 | Avilés | Asturias | 43.55544 | -5.9222466 |
4 | Abelardo González | 15176 | 171 | 167 | 4 | 3 | 242 | 86 | 0.50 | 38 | 0.22 | 47 | 0.27 | Sotrondio | Asturias | 43.27602 | -5.6048833 |
5 | Adjutorio Serrat | 6886 | 80 | 79 | 1 | 6 | 56 | 27 | 0.34 | 25 | 0.31 | 28 | 0.35 | Olot | Girona | 42.18222 | 2.4890211 |
7 | Adrián Guerrero | 127 | 2 | 1 | 1 | 1 | 48 | 1 | 0.50 | 1 | 0.50 | 0 | 0.00 | Blanes | Girona | 41.67562 | 2.7932391 |
9 | Alba | 90 | 1 | 1 | 0 | 0 | 70 | 0 | 0.00 | 0 | 0.00 | 1 | 1.00 | NA | NA | NA | NA |
Uno de los principales problemas que hemos encontrado durante el proceso de representación de los datos fueron los errores que cometía la función anterior a la hora de geolocalizar las diferentes ciudades que pasábamos. Los errores básicamente consistían en que las ubicaciones no eran correctas, por lo que aparecían jugadores en municipios que no les correspondían. Por eso, tras revisar detallada y cuidadosamente el proceso para todos las observaciones, hemos encontrado ciertos errores en determinadas ciudades que hemos solucionado de esta manera, después de adquirir sus coordenadas desde Google Maps, que también usa el sistema de coordenadas EPSG: 4326:
playersVCF <- playersVCF %>%
mutate(
lat = case_when(
Ciudad == "Arroyo de la Miel" ~ 36.5956,
Ciudad == "Almenara" ~ 39.7535,
Ciudad == "Puerto de Santa María" ~ 36.59597,
Ciudad == "Cartagena" ~ 37.6256,
Ciudad == "Teruel" ~ 40.34605,
Ciudad == "Durango" ~ 43.1719,
Ciudad == "Anglès" ~ 41.9566,
Ciudad == "Palencia" ~ 42.0098,
Ciudad == "Ibiza" ~ 38.9067,
TRUE ~ lat
),
long = case_when(
Ciudad == "Arroyo de la Miel" ~ -4.5522,
Ciudad == "Almenara" ~ -0.22298,
Ciudad == "Puerto de Santa María" ~ -6.2335,
Ciudad == "Cartagena" ~ -0.9964,
Ciudad == "Teruel" ~ -1.10577,
Ciudad == "Durango" ~ -2.63298,
Ciudad == "Anglès" ~ 2.6334,
Ciudad == "Palencia" ~ -4.5288,
Ciudad == "Ibiza" ~ 1.42003,
TRUE ~ long
)
)
Una vez superado uno de los principales obstáculos de este trabajo, convertimos nuestros datos a un objeto sf (datos espaciales) uniendo las dos columnas que teníamos reservadas para la latitud y la longitud, respectivamente. Usamos el crs = 4326 (sistema de coordenadas) porque, a pesar de estar trabajando para datos de España, tanto OSM como la librería leaflet que usaremos más tarde para representar los datos en el mapa trabajan con el sistema de referencia global, EPSG:4326 (WGS 84):
playersVCF_sf <- st_as_sf(playersVCF, coords = c("long", "lat"), na.fail = FALSE, crs = 4326)
kable(head(playersVCF_sf))
X1 | Nombre | Min | PJ | Tit | Sup | Cam | NJ | PG | %PG | PE | %PE | PP | %PP | Ciudad | Provincia | geometry |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Aarón Ñíguez | 52 | 3 | 1 | 2 | 1 | 101 | 2 | 0.67 | 0 | 0.00 | 1 | 0.33 | Elche | Alicante | POINT (-0.6988391 38.26533) |
2 | Abdón García | 7380 | 82 | 82 | 0 | 0 | 60 | 34 | 0.41 | 14 | 0.17 | 34 | 0.41 | Avilés | Asturias | POINT (-5.922247 43.55544) |
4 | Abelardo González | 15176 | 171 | 167 | 4 | 3 | 242 | 86 | 0.50 | 38 | 0.22 | 47 | 0.27 | Sotrondio | Asturias | POINT (-5.604883 43.27602) |
5 | Adjutorio Serrat | 6886 | 80 | 79 | 1 | 6 | 56 | 27 | 0.34 | 25 | 0.31 | 28 | 0.35 | Olot | Girona | POINT (2.489021 42.18222) |
7 | Adrián Guerrero | 127 | 2 | 1 | 1 | 1 | 48 | 1 | 0.50 | 1 | 0.50 | 0 | 0.00 | Blanes | Girona | POINT (2.793239 41.67562) |
9 | Alba | 90 | 1 | 1 | 0 | 0 | 70 | 0 | 0.00 | 0 | 0.00 | 1 | 1.00 | NA | NA | POINT EMPTY |
Ahora, para contextualizar los datos obtenidos y representarlos correctamente en el mapa de España, obtuvimos los 8131 municipios que componen nuestro país, sus nombres, geometrías, provincia y comunidad autónoma, entre otras variables, con el paquete mapSpain, y lo guardamos en otro objeto nuevo: spain_mun:
spain_mun <- esp_get_munic(epsg = "4326", moveCAN = FALSE)
kable(head(spain_mun))
codauto | ine.ccaa.name | cpro | ine.prov.name | cmun | name | LAU_CODE | geometry | |
---|---|---|---|---|---|---|---|---|
382 | 01 | Andalucía | 04 | Almería | 001 | Abla | 04001 | POLYGON ((-2.77744 37.23836… |
379 | 01 | Andalucía | 04 | Almería | 002 | Abrucena | 04002 | POLYGON ((-2.88984 37.09213… |
374 | 01 | Andalucía | 04 | Almería | 003 | Adra | 04003 | POLYGON ((-2.93161 36.75079… |
375 | 01 | Andalucía | 04 | Almería | 004 | Albánchez | 04004 | POLYGON ((-2.13138 37.29959… |
358 | 01 | Andalucía | 04 | Almería | 005 | Alboloduy | 04005 | POLYGON ((-2.70077 37.09674… |
373 | 01 | Andalucía | 04 | Almería | 006 | Albox | 04006 | POLYGON ((-2.15335 37.54576… |
Sin embargo, nos dimos cuenta de otro problema que nos iba a dificultar bastante las cosas, sobre todo a la hora de etiquetar los datos en el mapa: los nombres de los diferentes pueblos. La existencia de los diferentes idiomas oficiales en nuestro territorio fue uno de los principales detonantes del inconveniente, siendo los nombres de los municipios vascos los que causaban mayores complicaciones, pese a que en su gran mayoría eran reconocidos tanto en Español como en Euskera, y los que no únicamente tuvimos que tener cuidado de darnos cuenta para que no se perdiera ningún dato y traducirlo. Por otra parte, también encontramos otros pueblos, generalmente valencianos, catalanes o gallegos con denominaciones muy variadas, habiendo muchos que empezaban por Les, por L’ o por O, y mientras nosotros lo poníamos al principio de cada pueblo, (por ejemplo: L’ Alcúdia), mapSpain lo ponía al final (Alcúdia, L’). Este problema se atajó creando una función que luego aplicaríamos a nuestro objeto creado previamente spain_mun:
Con los municipios y sus datos geoespaciales ya guardados, los jugadores con la ubicación de sus ciudades natales y los problemas tanto de ubicación como de denominación resueltos, el siguiente paso era combinar los dos objetos:
playersVCF_mun <- st_join(playersVCF_sf, spain_mun, join = st_within)
kable(head(playersVCF_mun))
X1 | Nombre | Min | PJ | Tit | Sup | Cam | NJ | PG | %PG | PE | %PE | PP | %PP | Ciudad | Provincia | geometry | codauto | ine.ccaa.name | cpro | ine.prov.name | cmun | name | LAU_CODE |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Aarón Ñíguez | 52 | 3 | 1 | 2 | 1 | 101 | 2 | 0.67 | 0 | 0.00 | 1 | 0.33 | Elche | Alicante | POINT (-0.6988391 38.26533) | 10 | Comunitat Valenciana | 03 | Alicante/Alacant | 065 | Elche / Elx | 03065 |
2 | Abdón García | 7380 | 82 | 82 | 0 | 0 | 60 | 34 | 0.41 | 14 | 0.17 | 34 | 0.41 | Avilés | Asturias | POINT (-5.922247 43.55544) | 03 | Asturias, Principado de | 33 | Asturias | 004 | Avilés | 33004 |
4 | Abelardo González | 15176 | 171 | 167 | 4 | 3 | 242 | 86 | 0.50 | 38 | 0.22 | 47 | 0.27 | Sotrondio | Asturias | POINT (-5.604883 43.27602) | 03 | Asturias, Principado de | 33 | Asturias | 060 | San Martín del Rey Aurelio | 33060 |
5 | Adjutorio Serrat | 6886 | 80 | 79 | 1 | 6 | 56 | 27 | 0.34 | 25 | 0.31 | 28 | 0.35 | Olot | Girona | POINT (2.489021 42.18222) | 09 | Cataluña | 17 | Girona | 114 | Olot | 17114 |
7 | Adrián Guerrero | 127 | 2 | 1 | 1 | 1 | 48 | 1 | 0.50 | 1 | 0.50 | 0 | 0.00 | Blanes | Girona | POINT (2.793239 41.67562) | 09 | Cataluña | 17 | Girona | 023 | Blanes | 17023 |
9 | Alba | 90 | 1 | 1 | 0 | 0 | 70 | 0 | 0.00 | 0 | 0.00 | 1 | 1.00 | NA | NA | POINT EMPTY | NA | NA | NA | NA | NA | NA | NA |
De esta manera, lo que hemos hecho es unir ambos objetos pero de forma que, si un punto de un jugador de playersVCF_sf está dentro del polígono de un municipio en spain_mun, herede sus características tales como el nombre (aquí podemos ver la importancia de la corrección anterior para hacer más consistentes los nombres), provincia o comunidad, ya mencionadas antes. Sin embargo, no se guardan dichos polígonos de los pueblos, ya que eso es algo que utilizaremos más adelante.
Ahora agruparemos los datos de playersVCF_sf, concretamente los nombres de los jugadores, en función de los nombres de los municipios a los que pertenecen, además de sus respectivos puntos geográficos (que no polígonos de los mismos, reiteramos):
municipios_seleccionados <- playersVCF_mun %>%
group_by(name) %>%
summarise(Nombres = paste(Nombre, collapse = ", "))
kable(head(municipios_seleccionados))
name | Nombres | geometry |
---|---|---|
A Coruña | Carlos Pellicer, Jason Remeseiro, José María Martín, José Reverter, Manolete Ríos, Nico González, Waldo Botana | POINT (-8.395943 43.37097) |
Aielo de Malferit | Rafael Barber | POINT (-0.5911695 38.88036) |
Alaquàs | Francisco Cotino, Manuel Ruz, Matías Rubio, Miguel Pallardó | POINT (-0.46098 39.45729) |
Albaida | Daniel Olcina | POINT (-0.5181895 38.83867) |
Albal | José Paredes, Salva Ruiz | POINT (-0.4150821 39.39564) |
Alboraia / Alboraya | Fernando Giner | POINT (-0.34948 39.501) |
Como último paso antes de llevar a cabo la representación del mapa interactivo, unimos municipios_seleccionados con spain_mun, aplicando esta vez sí, los polígonos. Por tanto lo que conseguimos con el siguiente código es agregar a cada polígono la lista de jugadores que pertenecen a él. Dicho de otra forma, estamos obteniendo todos los pueblos de España y a cada uno le asociamos el nombre de los futbolistas que hayan nacido en él o se queda en blanco en caso de no tener representantes. Dada esta explicación, va a ser lógico esperar que una gran cantidad de pueblos no tengan jugadores asociados y por tanto es completamente normal que hayan columnas con muchos NA’s.
municipios_final <- st_join(spain_mun, municipios_seleccionados, join = st_intersects)
kable(head(municipios_final))
codauto | ine.ccaa.name | cpro | ine.prov.name | cmun | name.x | LAU_CODE | name.y | Nombres | geometry | |
---|---|---|---|---|---|---|---|---|---|---|
382 | 01 | Andalucía | 04 | Almería | 001 | Abla | 04001 | NA | NA | POLYGON ((-2.77744 37.23836… |
379 | 01 | Andalucía | 04 | Almería | 002 | Abrucena | 04002 | NA | NA | POLYGON ((-2.88984 37.09213… |
374 | 01 | Andalucía | 04 | Almería | 003 | Adra | 04003 | NA | NA | POLYGON ((-2.93161 36.75079… |
375 | 01 | Andalucía | 04 | Almería | 004 | Albánchez | 04004 | NA | NA | POLYGON ((-2.13138 37.29959… |
358 | 01 | Andalucía | 04 | Almería | 005 | Alboloduy | 04005 | NA | NA | POLYGON ((-2.70077 37.09674… |
373 | 01 | Andalucía | 04 | Almería | 006 | Albox | 04006 | NA | NA | POLYGON ((-2.15335 37.54576… |
Output
Se han obtenido como resultado dos conjuntos de datos para que, en función de la utilidad deseada, podamos elegir entre uno u otro. Pese a que el que nosotros utilizaremos a continuación para la representación del mapa es el que hemos almacenado en municipios_final, creemos que el obtenido previo a este (municipios_seleccionados), es más visual y representativo a la hora de verlos en formato tabla. Esto se debe a que, mientras que el primero contiene las geometrías necesarias de absolutamente todos los pueblos nacionales (tengan representación o no) para poder destacarlos en caso favorable, apareciendo así con miles de observaciones prácticamente inservibles, el segundo contiene única y exclusivamente los nombres de aquellos municipios de los que sí ha salido al menos un jugador (además de una categoría NA que contiene a los futbolistas de los cuales no se han podido encontrar datos de nacimiento).
Este último lo podemos guardar ya en formato GeoPackage con la función st_write:
st_write(municipios_seleccionados, "Municipios Jugadores VCF.gpkg")
El otro todavía vamos a emplearlo para generar un mapa que nos permita visualizar de forma interactiva las localidades de residencia de cada jugador, de modo que si pinchamos en uno de estos pueblos sombreados, aparecen los nombres de los jugadores procedentes del mismo.
# Aplicamos la paleta de colores
colores_vcf <- c("#F5A503", "#000000", "#FFFAF0", "#D4AF37")
paleta_colores <- colorFactor(palette = colores_vcf, domain = municipios_final$name.y)
# Graficamos
leaflet() %>%
addTiles() %>%
addPolygons(data = municipios_final,
fillColor = ~ifelse(!is.na(name.y), paleta_colores(name.y), "transparent"),
fillOpacity = ~ifelse(!is.na(name.y), 0.7, 0),
color = "black",
weight = 1,
popup = ~paste("Jugadores de", name.x, ":", Nombres),
highlightOptions = highlightOptions(
weight = 3,
color = "red",
bringToFront = TRUE
))
Como ya hemos presentado antes, este mapa representa todos los pueblos de España y sombrea con color aquellos que cuentan con al menos un representante futbolístico en la historia del Valencia CF. Al clicar en cada uno de sus términos municipales, aparece el nombre de dicho municipio y también el de todos los jugadores que, tras nacer allí, llegaron a debutar en competición oficial en el primer equipo del Valencia CF. Es interesante ver la variedad y distribución de estos jugadores, y se pueden extraer muchas conclusiones como, el que a pesar de que las ciudades más grandes cuenten con la mayor representación, en cualquier pueblito de cualquier rincón de España puede aparecer un gran futbolista.
Una vez visto y curioseado nuestro mapa, estamos listos para descargar el conjunto de datos definitivo, que cuenta con todas las poblaciones españolas:
st_write(municipios_final, "Todos los municipios - Jugadores VCF.gpkg")
Ambos ficheros generados con este procedimiento se pueden descargar en formato GeoPackage directamente de aquí.
Proyectos de Innovación Educativa Emergente PIEE-2737007 y PIEE-3325394