Una mirada al Soccer Analytics usando R — Parte I

Poco tiempo atrás participé como speaker en el satRday 2018 que se hizo en Santiago de Chile, con una charla titulada igual que este post (slides aquí).

Mi intención fue, por un lado, proponer una categorización de los tipos de análisis cuantitativos que se acostumbra a realizar en el área de Soccer Analytics, incluyendo algunos de los últimos ejemplos que la misma comunidad ha desarrollado; y al mismo tiempo compartir y difundir mi proyecto personal Dato Fútbol, el cual está hecho completamente con las herramientas ligadas al mundo de R (RStudio, blogdown, Shiny, ggplot2, dplyr ,etc.) como se aprecia en el siguiente esquema que sigue el workflow típico de ciencia de datos.

Elaboración propia

Entonces, la idea ahora con este post es detallar algunos de los puntos que considero más relevantes y compartir algo de código en R.

Vamos con lo primero: Propuesta de categorización

Elaboración propia

1) Estadísticas históricas

La primera categoría incluye los típicos datos históricos que se usan para describir, comparar y/o dar un contexto previo o posterior a algún partido o torneo.

Lo aplican principalmente los medios digitales tales como diarios (periódicos) así como también cuentas de twitter famosas: @pelotazo, @elluchoreyes, @golynumeros, etc. Acá un ejemplo sobre la campaña del último campeón del fútbol chileno (2018), Universidad Católica:

Fuente: La Tercera

Se trata principalmente de rankings, proporciones, distribuciones y en algunos casos conexiones o flujos, por lo que los tipos de visualizaciones comunes son barras, tortas, histogramas, tablas, entre otros. Es común también que este tipo de análisis conviva muy bien dentro de las infografías.

Los datos generalmente vienen de fuentes privadas dado que requieren un arduo trabajo previo de recolección. Sin embargo, es posible hacer algo de web scraping para conseguir resultados de manera “gratuita”, desde por ejemplo los sitios webs de FIFA, Conmebol, ESPN, Wikipedia, CDF, etc.

También existen repositorios públicos con datos de resultados históricos, aunque principalmente asociados a las principales ligas europeas o campeonatos internacionales entre selecciones (Ej: Kaggle, Github).


Ejemplo con R

A continuación les comparto algo de código en R para obtener visualizaciones acerca e las formaciones iniciales de los equipos en cada juego, utilizando la base de datos de Kaggle antes citada.

Para ello se consideran todos los partidos de Premier League, La Liga, Bundesliga y Seria A, entre las temporadas 2008/09 y 2015/16 (8 años), equivalente a más de 10 mil partidos.

a) Primero es necesario conectarse a la base de datos y hacer algo de procesamiento para codificar la ubicación de los jugadores en el campo de juego y obtener las formaciones iniciales de los equipos, lo cual es arbitario, pero sigue una lógica de acuerdo a la siguiente ilustración:

  • La coordenada X determina posición de izquierda a derecha (es necesario corregir la ubicación del arquero desde X=1 a X=5)
  • La coordenada Y determina posición desde defensas a delanteros. Arbitrariamente se divide el medio campo entre Y=6 e Y=7 (línea roja).

El código para hacer esto, codificar las formaciones y obtener la tabla que se usará a continuación se puede ver en detalle acá.

b) Ahora el primer gráfico para rankear las formaciones iniciales para equipos en condicón de Local y Visita:

library(dplyr)
library(ggplot2)
library(RColorBrewer)
t1 <- read.csv("tabla1_.csv", header = T)
Locales <- t1[,c('league_id','season','resultado','formLocal')]
colnames(Locales)[4] <- "form"
Locales <- cbind(Locales,"L")
colnames(Locales)[5] <- "Team"
Visitas <- t1[,c('league_id','season','resultado','formVisita')]
colnames(Visitas)[4] <- "form"
Visitas <- cbind(Visitas,"V")
colnames(Visitas)[5] <- "Team"
t2 <- rbind(Locales,Visitas)
# distribucion formaciones
## local
local_form <- t1 %>% count(formLocal) %>% mutate(S = "L")
names(local_form)[1] <- "form"
## away
away_form <- t1 %>% count(formVisita) %>% mutate(S = "V")
names(away_form)[1] <- "form"
## ambos
form <- rbind(local_form, away_form)
ft <- aggregate(n ~ form, data=form, FUN=sum)
ft <- ft[order(ft$n,decreasing = F),]
# gráfico
pform1 <- ggplot(t2, aes(x = form)) +
geom_bar(stat="count", aes(fill=factor(Team)), alpha=0.4,
position = position_identity()) +
coord_flip()
p1 = pform1 + theme_bw() +
labs(x="Formaciones", y="Número de partidos") +
scale_fill_brewer(palette = "Set1", name="Equipo\nLocal/Visita") +
theme(legend.background = element_rect(fill="gray96"),
axis.text.x = element_text(vjust=0.5, size=10),
axis.text.y = element_text(vjust=0.5, size=10),
axis.title.x = element_text(face="bold", size=12, margin=margin(8,8,0,0)),
axis.title.y = element_text(face="bold", size=12, margin=margin(8,8,0,0)),
legend.position=c(0.85,0.35),
legend.title = element_text(size=10, face="bold")) +
scale_x_discrete(limits=t(ft[6:21,1])) +
ggtitle(label="Formaciones iniciales", subtitle = "Dataset: 10733 partidos de ligas BBVA, Serie A, Bundesliga y Premier.\nEntre 2008/2009 y 2015/2016.\nEquipos Local y Visita")
p1
  • Queda claro que las formaciones iniciales más utilizadas son 4–2–3–1, 4–4–2 y 4–3–3.
  • Se evidencia la supremacía de la línea de 4 por sobre la de 3. La mejor exponente de la “línea de 3” (3–5–2) queda relegada al 5to lugar.
  • No hay diferencias notorias entre las formaciones usadas por equipos locales y equipos visitas

c) También separar por liga usando facetas ilustra sus diferencias:

t2 <- t2 %>% mutate(league=if_else(league_id==1729, 'Premier League', if_else(league_id==7775, 'Bundesliga', 
if_else(league_id==10223, 'Serie A', 'La Liga'))) )
pform2 <- ggplot(t2, aes(x = form)) + 
geom_bar(stat = "count", aes(fill=factor(league))) +
coord_flip()
p2 = pform2 + facet_grid(~ league) + theme_bw() +
labs(x="Formaciones", y="Número de partidos") +
theme(axis.text.x = element_text(vjust=0.5, size=10),
axis.text.y = element_text(vjust=0.5, size=10),
axis.title.x = element_text(face="bold", size=12, margin=margin(8,8,0,0)),
axis.title.y = element_text(face="bold", size=12, margin=margin(8,8,0,0)),
strip.text.x = element_text(face="bold", size=10),
strip.background = element_rect(fill="ghostwhite"),
legend.position="none") +
scale_x_discrete(limits=t(ft[6:21,1])) +
ggtitle(label="Formaciones iniciales por ligas", subtitle = "Dataset: 10733 partidos de ligas BBVA, Serie A, Bundesliga y Premier.\nEntre 2008/2009 y 2015/2016.\nEquipos Local y Visita")
p2
  • La Liga y Premier League tienden a concentrar sus formaciones iniciales principalmente en solo 3 o 4 tipos: 4–2–3–1, 4–4–2 y 4–3–3 en ambas ligas; y aparece el 4–5–1 en la Premier con una cantidad considerable (es la liga en la que más se usa este esquema). En La Liga destaca ampliamente 4–2–3–1 por sobre todas las otras formaciones.
  • Por otro lado, Bundesliga y Serie A tienen un comportamieto más homogéneo, repartiéndose el uso de formaciones en distintos esquemas. Además de los esquemas típicos, en Bundesliga aparecen algunos esquemas como 4–1–4–1, 4–1–3–2 y 4–2–2–2, mientras que en Serie A aparecen esquemas con línea de 3: 3–5–2 y 3–6–1.
  • 4–2–3–1 gana en La Liga y Bundesliga, 4–4–2 en Premier y 4–3–3 en Serie A.

El post completo acerca de las formaciones lo pueden revisar aquí.


En los próximos post seguiré con la descripción y ejemplos de las categorías restantes. Hasta la próxima!