Por qué empezar con StatsBomb open data

StatsBomb publica un conjunto de competiciones gratuitas con datos de eventos completos: cada pase, conducción, presión y disparo, con coordenadas y contexto. Es el mejor arenero de la analítica de fútbol — sin API key, sin negociar términos, sin scraping.

El catálogo completo vive en el repositorio open-data de GitHub.

Paso 1 — Elige una competición y carga los eventos

El paquete statsbombpy envuelve el JSON crudo:

from statsbombpy import sb

competitions = sb.competitions()
matches = sb.matches(competition_id=11, season_id=90)   # La Liga 2020/21
events = sb.events(match_id=matches.iloc[0].match_id)

Si prefieres los ficheros crudos — recomendable para aprender, porque ves el esquema — descarga events/{match_id}.json del repositorio y parsea con pandas.json_normalize.

Paso 2 — Convierte eventos en disparos

shots = (
    events[events.type == "Shot"]
    .assign(
        x=lambda df: df.location.apply(lambda loc: loc[0]),
        y=lambda df: df.location.apply(lambda loc: loc[1]),
        goal=lambda df: df.outcome == "Goal",
    )
    [["x", "y", "goal", "player", "shot_statsbomb_xg"]]
)

print(shots.groupby("player").agg(shots=("goal", "size"), goals=("goal", "sum")))

Dos cosas a notar: las coordenadas están en un campo de 120×80, y los eventos ya traen shot_statsbomb_xg. Usa esa columna para validar tu propio modelo después.

Paso 3 — Dibuja el mapa de disparos

import mplsoccer
import matplotlib.pyplot as plt

pitch = mplsoccer.Pitch(pitch_type="statsbomb", pitch_color="#0d1117")
fig, ax = pitch.draw()

sizes = shots["shot_statsbomb_xg"] * 900 + 60
colors = shots["goal"].map({True: "#00e08a", False: "#4b5563"})
pitch.scatter(shots.x, shots.y, s=sizes, c=colors, alpha=0.85, ax=ax)
ax.set_title("Shots — size = xG, colour = goal", color="white")
plt.show()

Paso 4 — Hazlo repetible

Un pipeline que descarga, transforma y dibuja en un solo script se vuelve inmanejable al tercer partido. Sepáralo pronto:

  • ingest/ — descarga el JSON crudo y guárdalo sin tocar (cachea todo; la API es lenta y tiene límites).
  • transform/ — parsea eventos a dataframes tidy, una función por entidad (shots, passes, pressures).
  • analysis/ — funciones puras sobre los frames: agregaciones, ventanas móviles, comparaciones.
  • notebooks/ — solo exploración; en cuanto una transformación se reutiliza, pasa a transform/.

Es el mismo patrón que usa cualquier proyecto serio de datos de fútbol, y el que sobrevive al contacto con un segundo dataset.

Dónde seguir

  1. Variables para xG — añade presión, parte del cuerpo, disparos a la primera; compara tu AUC con shot_statsbomb_xg.
  2. Redes de pases — agrega pases por pareja de jugadores y posición.
  3. Métricas de presión — cuenta presiones por zona y observa qué equipos rompen antes la estructura.

Elige una pregunta, construye el pipeline más pequeño que la responda y publica lo que aprendas. Ese bucle — pregunta, datos, respuesta — es el trabajo real.