El último Barça campeón (temporada 22-23)

La radiografía de un equipo (casi) imbatible y su camino al título

trabajo BigData
futbol
Autorcito
Afiliación

Julio Saad (jusame@alumni.uv.es)

Fecha de Publicación

30 de diciembre de 2024

Resumen
El objeto del estudio es analizar la evolución del FC Barcelona en la temporada 2022-2023 y como acaba conquistando el título de la Liga Española. Para ayudar a este análisis se parte de los resultados en esta competición y las estadísticas de los jugadores del equipo.

Introducción al trabajo

Para realizar nuestra empresa descargaremos de Kagle un par de conjuntos de datos que serán la base del trabajo. El primer conjunto de datos se llama LaLiga_Matches y se puede encontar aquí. Este conjunto contiene todas las fechas, equipos, temporadas, goles y resultados desde la temporada 1995-1996.

El segundo conjunto de datos se llama Big 5 European Leagues Player Stats 2022-23 y se puede encontrar aquí. De aquí solos nos descargaremos un archivo csv llamado stats que es una especie de resumen combinado del resto de archivos.

Aparte de eso, utilizaremos una serie de paquetes básicos para trabajar los datos con ellos:

Cargaremos todo así dentro del programa de esta forma:

Código

library(dplyr)
library(tidyr)
library(ggplot2)
library(gganimate)


partidos <- read.csv("./assets/LaLiga_Matches.csv")
jugadores <- read.csv("./assets/Big5-statsStats22-23.csv")
#en esta ultima IMPORTANTE: al importar selecionar Heading: Yes

Ahora realizaremos una serie de pasos para modificar el bruto de los datos y poder hacerlos más manejables para trabajar:

Código

#tenemos que arreglar los datos ya que vienen en bruto 
#(incluyen todos los partidos y todos los jugadores)

#primero filtramos el bruto por la temporada 22-23 y 
#los resultados de los partidos del FC Barcelona

barcelona_total <- partidos %>% 
  filter(Season=="2022-23")%>%
  filter(HomeTeam=="Barcelona" | AwayTeam=="Barcelona")

#Una vez hecho modificamos el nombre de las columnas 
#y las pasamos al castellano

colnames(barcelona_total)[1] <-"temporada"
colnames(barcelona_total)[2] <-"fecha"
colnames(barcelona_total)[3] <-"equipo_local"
colnames(barcelona_total)[4] <-"equipo_visitante"
colnames(barcelona_total)[5] <-"goles_local_final"
colnames(barcelona_total)[6] <-"goles_visitante_final"
colnames(barcelona_total)[7] <-"resultado_final"
colnames(barcelona_total)[8] <-"goles_local_descanso"
colnames(barcelona_total)[9] <-"goles_visitante_descanso"
colnames(barcelona_total)[10] <-"resultado_descanso"


#a partir de aqui empezamos a modificar el df sobre el que trabajaremos:
#barcelona_total para quedarnos con los partidos 
#que juega de local o visitante 
#o para sacar las medias de los goles que marca cuando es local o visitante

barcelona_local <- barcelona_total %>%
  filter (equipo_local=="Barcelona")

barcelona_visit <- barcelona_total %>%
  filter (equipo_visitante=="Barcelona")

media_goles_local <- barcelona_local %>%
  summarise (media_goles_local = mean(goles_local_final))

media_goles_visit <- barcelona_visit %>%
  summarise (media_goles_visit = mean (goles_visitante_final))


#ahora modificaremos los datos de los jugadores 

jugadores_barcelona <- jugadores %>%
  filter (Squad == "Barcelona")  %>% #QUEREMOS SOLO LOS JUGADORES DEL BARÇA
  
  #Y SOLO ESTAS COLUMNAS
  select(Player, Pos, Born, Age, Starts, Min, Gls, Ast) %>% 
  
  #CAMBIO POSICIÓN ERIC GARCIA
  mutate (Pos =ifelse (Pos=="DF,MF", "DF", Pos)) %>% 
  #CAMBIO POSICIÓN GAVI
  mutate (Pos =ifelse (Pos=="MF,FW", "MF", Pos)) %>% 
  #CAMBIO POSICIÓN FERRAN Y P.TORRE
  mutate (Pos =ifelse (Pos=="FW,MF", "FW", Pos)) %>% 

  #PASAMOS LENGUAJE + CÓMODO
  mutate (Pos =ifelse (Pos=="DF", "Defensa", Pos)) %>% 
  mutate (Pos =ifelse (Pos=="GK", "Portero", Pos)) %>%
  mutate (Pos =ifelse (Pos=="MF", "Centrocampista", Pos)) %>%
  mutate (Pos =ifelse (Pos=="FW", "Delantero", Pos))


#modificamos los nombres de las columnas
colnames(jugadores_barcelona)[1] <-"jugador"
colnames(jugadores_barcelona)[2] <-"posicion"
colnames(jugadores_barcelona)[3] <-"año"
colnames(jugadores_barcelona)[4] <- "edad"
colnames(jugadores_barcelona)[5] <-"titularidades"
colnames(jugadores_barcelona)[6] <-"minutos_jugados"
colnames(jugadores_barcelona)[7] <-"goles"
colnames(jugadores_barcelona)[8] <-"asistencias"

El primer dataset contiene observaciones sobre un conjunto de 38 jornadas de la temporada 22-23 de La Liga. Hay 10 variables (temporada, fecha, equipo local, equipo visitante, resultado final, resultado al descanso, goles del equipo local al final y al descanso, goles del equipo visitante al final y al descanso).

El segundo dataset contiene observaciones sobre un conjunto de 29 jugadores de la plantilla que forma el equipo en la temporada 22-23 de La Liga. Tendremos 8 variables (nombre, posición, edad, año de nacimiento, titularidades, minutos jugados, goles, asistencias)


Ambientación

Para ilustrar y poner en contexto como se encontraba el equipo, colocaremos una foto de la plantilla con la que se contaba para afrontar la temporada:

Imagen 1: Plantilla, Entrenadores y Presidente del FC Barcelona para la temporada 2022-2023.

Cabe mencionar que sería la última temporada en la que el equipo disputaría sus partidos como local en su campo debido a la remodelación del estadio prevista al finalizar la temporada.

Para muestra un par de imágenes:

Imagen 2: Camp Nou antes

Y el Camp Nou futuro:

Imagen 3: Camp Nou futuro

Análisis de los partidos

Para realizar el análisis de los partidos realizaremos unos cuantos gráficos:

:::


Local: Gráfico para el resultado al descanso

Código

#gráfico 1
# COMO LOCAL Gráfico de barras para el resultado al descanso 
#A es Equipo Visitante, D es Empate y H es Equipo Local
goles_local_descanso <-
  ggplot(barcelona_local, aes(x = resultado_descanso, fill = resultado_descanso)) +
  geom_bar() +
  scale_fill_manual(values = c("H" = "blue", "D" = "yellow", "A" = "red")) +
  labs(
    title = "Resultados al descanso como Local",
    x = "Resultado",
    y = "Frecuencia",
    fill = "Resultado"
  ) +
  theme_minimal()


goles_local_descanso


Aquí podemos observar como más del doble de veces el Barcelona se fue ganando al descanso mientras jugaba como local de las que se fue empatando el partido. Sólo un mínimo de veces se fue perdiendo al descanso.


Local: Gráfico para el resultado al final del partido

Código
#gráfico 2
#COMO LOCAL Gráfico de barras para el resultado al final del partido
#A es Equipo Visitante, D es Empate y H es Equipo Local

goles_local_final<-
  ggplot(barcelona_local, aes(x = resultado_final, fill = resultado_final)) +
  geom_bar() +
  scale_fill_manual(values = c("H" = "blue", "D" = "yellow", "A" = "red")) +
  labs(
    title = "Resultados al final como Local",
    x = "Resultado",
    y = "Frecuencia",
    fill = "Resultado"
  ) +
  theme_minimal()

goles_local_final


La muestra de la casi imbatibilidad del equipo a domicilio. ¡¡Apenas perdió 1 partido en casa!!


Visitante: Gráfico para el resultado al descanso

Código
#gráfico 3
#COMO VISITANTE Gráfico de barras para el resultado al descanso
#A es Equipo Visitante, D es Empate y H es Equipo Local

goles_visit_descanso<-
  ggplot(barcelona_visit, aes(x = resultado_descanso, fill = resultado_descanso)) +
  geom_bar() +
  scale_fill_manual(values = c("H" = "blue", "D" = "yellow", "A" = "red")) +
  labs(
    title = "Resultados al descanso del como Visitante",
    x = "Resultado",
    y = "Frecuencia",
    fill = "Resultado"
  ) +
  theme_minimal()

goles_visit_descanso


Aquí vemos como la fortaleza mostrada por el equipo en las primeras partes en casa se diluye fuera. Existe mucho más equilibrio en el resultado entre el FC Barcelona y sus rivales al descanso.


Visitante: Gráfico para el resultado al final

Código
#gráfico 5
#COMO VISITANTE Gráfico de barras para el resultado al final
#A es Equipo Visitante, D es Empate y H es Equipo Local

goles_visit_final<- 
  ggplot(barcelona_visit, aes(x = resultado_final, fill = resultado_final)) +
  geom_bar() +
  scale_fill_manual(values = c("H" = "blue", "D" = "yellow", "A" = "red")) +
  labs(
    title = "Resultados al final como Visitante",
    x = "Resultado",
    y = "Frecuencia",
    fill = "Resultado"
  ) +
  theme_minimal()


goles_visit_final


Sin embargo, en las segundas partes, el equipo se acababa imponiendo de una manera bastante clara a lo largo del campeonato. Las veces que acabó ganando fuera superan a las que terminó empatando o perdiendo.


Local: Comparación de resultados al descanso y al final

Código
#gráfico 5
#Comparación de resultados al descanso y al final cuando el equipo era LOCAL
#A es Equipo Visitante, D es Empate y H es Equipo Local

df_largo_local <- barcelona_local %>% 
  pivot_longer (cols = c(resultado_descanso, resultado_final), names_to = "momento", values_to = "resultado") 

#Calculamos proporciones 
proporciones_local <- df_largo_local %>% 
  count(momento, resultado) %>% 
  group_by(momento) %>% 
  mutate(Prop = n / sum(n)) 

#Combinamos el grafico 
comp_local <-
  ggplot(proporciones_local, aes(x = resultado, y = Prop, fill = momento)) + 
  geom_bar(stat = "identity", position = "dodge") + 
  scale_fill_manual(values = c("resultado_descanso" = "yellow", "resultado_final" = "red")) + 
  labs( title = "Comparación de resultados al descanso y al final como Local", x = "Resultado", y = "Proporción", fill = "Momento" ) + 
  theme_minimal()

comp_local


Este gráfico permite un análisis más detallado:

Los partidos donde jugó como local que acabó perdiendo, los iba perdiendo al descanso en la misma proporción.

Por otro lado, proporcionalmente iba empatando más partidos de los que finalmente terminaron así.

Y para terminar, acabó ganando más partidos al final de los que iba ganando al descanso.


Visitante: Comparación de resultados al descanso y al final

Código
#Comparación de resultados al descanso y al final cuando el equipo era VISITANTE
#A es Equipo Visitante, D es Empate y H es Equipo Local

df_largo_visit <- barcelona_visit %>% 
  pivot_longer (cols = c(resultado_descanso, resultado_final), names_to = "momento", values_to = "resultado") 

#Calculamos proporciones 
proporciones_visit <- df_largo_visit %>% 
  count(momento, resultado) %>% 
  group_by(momento) %>% 
  mutate(Prop = n / sum(n)) 

#Combinamos el grafico 
comp_visit<- 
  ggplot(proporciones_visit, aes(x = resultado, y = Prop, fill = momento)) + 
  geom_bar(stat = "identity", position = "dodge") + 
  scale_fill_manual(values = c("resultado_descanso" = "yellow", "resultado_final" = "red")) + 
  labs( title = "Comparación de resultados al descanso y al final como Visitante", x = "Resultado", y = "Proporción", fill = "Momento" ) + 
  theme_minimal()

comp_visit


Siguiendo el modelo del gráfico anterior, los datos reflejan:

El equipo ganó como visitante más partidos en proporción a los que iba ganando al descanso.

El equipo empató menos partidos de los que iba empatando al descanso, pero en mucha menor proporción. Esto refleja la igualdad de los equipos que le competían en las primeras partes y que luego no le pudieron seguir.

Por último, el equipo acabó perdiendo casi los mismos partidos que perdía al descanso, es decir, pocas veces acabó ganando o empatando un partido que ya perdía al descanso.


Análisis de los jugadores

Para realizar el análisis de los jugadores también nos apoyaremos en unos cuantos gráficos:

:::


Goles y asistencias por posición

Código

#ahora cambiaremos al dataframe de los jugadores (jugadores_barcelona)

#GRAFICOS JUGADORES

#gráfico 7 
#GOLES Y ASISTENCIAS POR POSICION

ggplot(jugadores_barcelona, aes(x = posicion)) +
  geom_bar(aes(y = goles, fill = "Goles"), stat= "identity", position = "dodge") +
  geom_bar(aes(y = asistencias, fill = "Asistencias"), stat= "identity", position = "dodge") +
  scale_fill_manual(values = c("Goles" = "blue", "Asistencias" = "green")) +
  labs(
    title = "Goles y Asistencias por Posición",
    x = "Posición en el Campo",
    y = "Cantidad",
    fill = "Rendimiento"
  ) +
  theme_minimal()


Podemos observar que ningún portero metió gol (algo bastante obvio) pero tampoco dió ninguna asistencia de gol, lo que es menos probable teniendo en cuenta el gusto del club por los porteros que se manejen bien con los pies.

Por otra parte los defensas dieron algo más de 5 asistencias de gol pero no aportaron ningún gol, lo que puede reflejar que a balón parado no fueron suficiente amenaza.

Los centrocampistas aportaron números algo bajos al ataque, aunque su peso en el juego es difícil de medir con estadísticas.

Los delanteros del equipo fueron los que llevaron el peso de los números ofensivos de manera bastante clara.


Edad y rendimiento

Código

#gráfico 8
#EDAD VS RENDIMIENTO

jugadores_edad_rend <- jugadores_barcelona %>%
  mutate(edad = 2023 - año)

ggplot(jugadores_edad_rend, aes(x = edad, y = goles + asistencias)) +
  geom_point(aes(color = posicion), size = 4, alpha = 0.7) +
  scale_color_brewer(palette = "Set2") +
  labs(
    title = "Edad vs Rendimiento",
    x = "Edad del Jugador",
    y = "Goles + Asistencias",
    color = "Posición"
  ) +
  theme_minimal()


En este gráfico vemos como un par de delanteros en torno a la mediana de edad del equipo destacan pero el peso del ataque del equipo lo lleva a la espalda el delantero polaco fichado esa misma temporada, Robert Lewandowski, con 34 años y más de 30 aportaciones ofensivas (goles más asistencias).


Participaciones de titulares por posición

Código
#gráfico 9
#PARTICIPACIONES DE TITULARES POR POSICION

#Calculamos los porcentajes de titularidades por posición

titulares_pos <- jugadores_barcelona %>% 
  group_by(posicion) %>% 
  summarise(titularidades = sum(titularidades)) %>%
  mutate(porcentaje = 100 * titularidades / sum(titularidades))

#Gráfico "quesito" con porcentajes
ggplot(titulares_pos, aes(x = "", y = titularidades, fill = posicion)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(porcentaje, 1), "%")), 
            position = position_stack(vjust = 0.5)) +
  scale_fill_brewer(palette = "Pastel2") +
  labs(
    title = "Distribución de Titularidades por Posición",
    x = "",
    y = ""
  ) +
  theme_void()


En este gráfico observamos como donde menor rotación existe es en la portería, mientras que tanto en ataque como en el centro del campo, los titulares suelen repetir, donde mayores cambios se producen es entre los jugadores de la defensa. Esto muy probablemente se deba a la plaga de lesiones entre los centrales que le costó al equipo la eliminación de la Champions.


Rendimiento de jugadores por posición

Código
#gráfico 10
#RENDIMIENTO DE JUGADORES POR POSICION


grafico_mov <- jugadores_barcelona %>%
  group_by(año, posicion) %>%
  summarise(goles = sum(goles), asistencias = sum(asistencias))




graf <- ggplot(grafico_mov, aes(x = posicion, y = año, fill = goles + asistencias)) +
  geom_tile() +
  scale_fill_viridis_c() +
  labs(
    title = "Rendimiento por posición según el año de nacimiento",
    x = "Posición",
    y = "Año",
    fill = "Goles + Asistencias"
  ) +
  theme_minimal() +
  
  transition_time(año)

animate(graf, duration=10, fps= 10) 


En este gráfico observamos como el rendimiento en números lo domina Robert Lewandowski,uno de los jugadores más veteranos (aparece en el primer segundo del gráfico). También observamos como algunos jugadores entorno a la mediana de edad se reparten el peso (exactamente lo mismo que nos salía en un gráfico anterior).



Conclusiones

Como dejamos claro al principio, el equipo mantuvo un nivel de victorias exepcional, marcando un ritmo imposible de alcanzar para el resto de rivales, los de detrás en la tabla de clasificación y a los que se enfrentaba jornada a jornada. El jugador destacado de este campeonato sin duda es Lewandowski, el máximo productor ofensivo del equipo y el fichaje estrella de esa temporada.



Información sobre la sesión

Aquí abajo os dejo mi entorno de trabajo y paquetes utilizados para que lo disfrutéis!

current session info

─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.1 (2024-06-14 ucrt)
 os       Windows 11 x64 (build 22631)
 system   x86_64, mingw32
 ui       RTerm
 language (EN)
 collate  Spanish_Spain.utf8
 ctype    Spanish_Spain.utf8
 tz       Europe/Madrid
 date     2024-12-30
 pandoc   3.1.11 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)

─ Packages ───────────────────────────────────────────────────────────────────
 package      * version date (UTC) lib source
 cli            3.6.3   2024-06-21 [1] CRAN (R 4.4.1)
 clipr          0.8.0   2022-02-22 [1] CRAN (R 4.4.1)
 colorspace     2.1-1   2024-07-26 [1] CRAN (R 4.4.1)
 crayon         1.5.3   2024-06-20 [1] CRAN (R 4.4.1)
 desc           1.4.3   2023-12-10 [1] CRAN (R 4.4.1)
 details        0.3.0   2022-03-27 [1] CRAN (R 4.4.2)
 digest         0.6.37  2024-08-19 [1] CRAN (R 4.4.1)
 dplyr        * 1.1.4   2023-11-17 [1] CRAN (R 4.4.1)
 evaluate       0.24.0  2024-06-10 [1] CRAN (R 4.4.1)
 fansi          1.0.6   2023-12-08 [1] CRAN (R 4.4.1)
 farver         2.1.2   2024-05-13 [1] CRAN (R 4.4.1)
 fastmap        1.2.0   2024-05-15 [1] CRAN (R 4.4.1)
 generics       0.1.3   2022-07-05 [1] CRAN (R 4.4.1)
 gganimate    * 1.0.9   2024-02-27 [1] CRAN (R 4.4.1)
 ggplot2      * 3.5.1   2024-04-23 [1] CRAN (R 4.4.1)
 glue           1.7.0   2024-01-09 [1] CRAN (R 4.4.1)
 gtable         0.3.5   2024-04-22 [1] CRAN (R 4.4.1)
 hms            1.1.3   2023-03-21 [1] CRAN (R 4.4.1)
 htmltools      0.5.8.1 2024-04-04 [1] CRAN (R 4.4.1)
 htmlwidgets    1.6.4   2023-12-06 [1] CRAN (R 4.4.1)
 httr           1.4.7   2023-08-15 [1] CRAN (R 4.4.1)
 jsonlite       1.8.8   2023-12-04 [1] CRAN (R 4.4.1)
 knitr          1.48    2024-07-07 [1] CRAN (R 4.4.1)
 labeling       0.4.3   2023-08-29 [1] CRAN (R 4.4.0)
 lifecycle      1.0.4   2023-11-07 [1] CRAN (R 4.4.1)
 magick         2.8.5   2024-09-20 [1] CRAN (R 4.4.1)
 magrittr       2.0.3   2022-03-30 [1] CRAN (R 4.4.1)
 munsell        0.5.1   2024-04-01 [1] CRAN (R 4.4.1)
 pillar         1.9.0   2023-03-22 [1] CRAN (R 4.4.1)
 pkgconfig      2.0.3   2019-09-22 [1] CRAN (R 4.4.1)
 png            0.1-8   2022-11-29 [1] CRAN (R 4.4.0)
 prettyunits    1.2.0   2023-09-24 [1] CRAN (R 4.4.1)
 progress       1.2.3   2023-12-06 [1] CRAN (R 4.4.1)
 purrr          1.0.2   2023-08-10 [1] CRAN (R 4.4.1)
 R6             2.5.1   2021-08-19 [1] CRAN (R 4.4.1)
 RColorBrewer   1.1-3   2022-04-03 [1] CRAN (R 4.4.0)
 Rcpp           1.0.13  2024-07-17 [1] CRAN (R 4.4.1)
 rlang          1.1.4   2024-06-04 [1] CRAN (R 4.4.1)
 rmarkdown      2.28    2024-08-17 [1] CRAN (R 4.4.1)
 rstudioapi     0.16.0  2024-03-24 [1] CRAN (R 4.4.1)
 scales         1.3.0   2023-11-28 [1] CRAN (R 4.4.1)
 sessioninfo    1.2.2   2021-12-06 [1] CRAN (R 4.4.2)
 stringi        1.8.4   2024-05-06 [1] CRAN (R 4.4.0)
 tibble         3.2.1   2023-03-20 [1] CRAN (R 4.4.1)
 tidyr        * 1.3.1   2024-01-24 [1] CRAN (R 4.4.1)
 tidyselect     1.2.1   2024-03-11 [1] CRAN (R 4.4.1)
 tweenr         2.0.3   2024-02-26 [1] CRAN (R 4.4.1)
 utf8           1.2.4   2023-10-22 [1] CRAN (R 4.4.1)
 vctrs          0.6.5   2023-12-01 [1] CRAN (R 4.4.1)
 viridisLite    0.4.2   2023-05-02 [1] CRAN (R 4.4.1)
 withr          3.0.1   2024-07-31 [1] CRAN (R 4.4.1)
 xfun           0.47    2024-08-17 [1] CRAN (R 4.4.1)
 xml2           1.3.6   2023-12-04 [1] CRAN (R 4.4.1)
 yaml           2.3.10  2024-07-26 [1] CRAN (R 4.4.1)

 [1] C:/Users/draco/AppData/Local/R/win-library/4.4
 [2] C:/Program Files/R/R-4.4.1/library

──────────────────────────────────────────────────────────────────────────────


Reutilizar