Los mapas de tiros en el fútbol son representaciones visuales que proporcionan información sobre la ubicación y la frecuencia de los tiros realizados durante un partido. Estos mapas son herramientas valiosas para entrenadores, analistas y jugadores, ya que permiten analizar patrones y tendencias en las oportunidades de gol. Mediante la representación gráfica de las áreas desde las cuales se efectúan los disparos, se pueden identificar zonas de peligro, fortalezas y debilidades tanto del equipo propio como del adversario. Además, los mapas de tiros pueden incluir datos sobre la efectividad en cada área, destacando las posiciones desde las cuales se logran más goles, también puede contribuir a la toma de decisiones estratégicas y tácticas, ayudando a optimizar el rendimiento y mejorar la eficacia en la ejecución de tiros a puerta durante los encuentros de fútbol.
En este post, vamos a repasar cómo conectarnos a los datos abiertos de StatsBomb para lograr crear una visualización de mapa de tiros. El código presentado está elaborado de tal forma que puede utilizarse para cualquier partido que desees, únicamente realizando pequeños ajustes.
En este caso, vamos a acceder a los datos de la final de la Copa Africana de Naciones AFCON entre Costa de Marfil y Nigeria.
Importación de librerías
Recuerda que, si te falta alguna de las librerías, puedes instalarla con el comando pip install nombre_librería
import pandas as pd
import matplotlib.pyplot as plt
from statsbombpy import sb
from mplsoccer import Sbopen, VerticalPitch
Accedemos a la lista de competiciones abiertas de StatsBomb
Los valores de las columnas competition_id y season_id nos permiten acceder a la competición.
competiciones = sb.competitions()
competiciones
Acceder a la competición
parser = Sbopen()
df_afcon = parser.match(1267, 107)
Lista de partidos
Listamos los partidos de la competición y ordenamos para que el último partido, es decir la final, se muestre primero. La columna match_id almacena el código del partido.
df_afcon.sort_values('match_date', ascending=False)
Accedemos a los datos del partido, en este caso la Final de la AFCON
partido = sb.events(match_id=3923881)
Filtramos los tiros en un nuevo df y obtenemos el valor del número de filas y columnas.
tiros = partido[partido['type']=='Shot']
tiros.shape
Mostramos el nombre de las columnas
tiros.columns
Determinamos las coordenadas de los tiros
El código crea una copia del DataFrame original tiros, luego expande los diccionarios dentro de la columna ‘location’ en nuevas columnas ‘x’ e ‘y’, y finalmente muestra las columnas ‘x’, ‘y’ y ‘location’.
tiros = tiros.copy()
tiros[['x', 'y']] = tiros['location'].apply(pd.Series)
tiros.loc[:, ['x', 'y', 'location']]
Obtenemos el número de tiros de cada equipo
Es importante fijarse en el nombre exacto de los equipos, debido a que esta información se debe utilizar tal cual como se muestra para realizar filtrados posteriores.
tiros.possession_team.value_counts()
Generamos la primera visualización
Este paso nos permite validar y confirmar que las acciones realizadas anteriormente se llevaron a cabo correctamente.
pitch = VerticalPitch(
half=True
)
fig, ax = pitch.draw(figsize=(10, 8))
sc = pitch.scatter(tiros["x"], tiros["y"],
ax=ax)
Diferenciar los tiros de cada equipo por colores
Ahora viene lo interesante. Vamos a diferenciar los tiros de cada equipo asignando colores. Para ello, creamos inicialmente dos dataframes con los tiros correspondientes a cada equipo. Luego, realizamos la asignación de colores mediante código hexadecimal. Finalmente, generamos la segunda visualización en este tutorial. Es importante destacar que en esta representación utilizamos shot_statsbomb_xg para que los círculos que representan los tiros varíen de tamaño según su valor de goles esperados (xG).
# Dividir df en dos partes, una para cada equipo
equipo1_tiros = tiros[tiros["team"] == "Côte d'Ivoire"]
equipo2_tiros = tiros[tiros["team"] == "Nigeria"]
# Asignar color a cada equipo
equipo1_color = "#F78710"
equipo2_color = "#078B55"
#Segunda visualización de mapa de tiros
pitch = VerticalPitch(
half=True
)
fig, ax = pitch.draw(figsize=(10, 8))
# Equipo1 tiros:
equipo1_sc = pitch.scatter(equipo1_tiros["x"], equipo1_tiros["y"],
s=equipo1_tiros.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo1_color,
ax=ax,
label="CIV")
# Equipo2 shots:
equipo2_sc = pitch.scatter(equipo2_tiros["x"], equipo2_tiros["y"],
s=equipo2_tiros.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo2_color,
ax=ax,
label="NGA")
ax.legend()
Visualización final
Para la última visualización, vamos a distinguir entre los goles y los tiros de cada equipo. Necesitamos crear nuevos dataframes para separar los goles de los tiros que no terminaron en gol para cada equipo. Finalmente, en el gráfico, utilizamos marker=»football» para representar un balón en los tiros que resultaron en gol.
#Separamos goles y no-goles de equipo1
equipo1_goles = equipo1_tiros[equipo1_tiros.shot_outcome == 'Goal']
equipo1_no_goles = equipo1_tiros[equipo1_tiros.shot_outcome != 'Goal']
#Separamos goles y no-goles de equipo2
equipo2_goles = equipo2_tiros[equipo2_tiros.shot_outcome == 'Goal']
equipo2_no_goles = equipo2_tiros[equipo2_tiros.shot_outcome != 'Goal']
#Visualización final de mapa de tiros
pitch = VerticalPitch(
half=True
)
fig, ax = pitch.draw(figsize=(10, 8))
# Equipo1 goles:
equipo1_sc_g = pitch.scatter(equipo1_goles["x"],
equipo1_goles["y"],
s=equipo1_goles.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo1_color,
marker="football",
ax=ax,
label="CIV goles")
# Equipo2 no-goles tiros:
equipo1_sc_ng = pitch.scatter(equipo1_no_goles["x"],
equipo1_no_goles["y"],
s=equipo1_no_goles.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo1_color,
ax=ax,
label="CIV tiros")
# Equipo2 goles:
equipo2_sc_g = pitch.scatter(equipo2_goles["x"],
equipo2_goles["y"],
s=equipo2_goles.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo2_color,
marker="football",
ax=ax,
label="NGA goles")
# Equipo2 no-goles:
equipo2_sc_ng = pitch.scatter(equipo2_no_goles["x"],
equipo2_no_goles["y"],
s=equipo2_no_goles.shot_statsbomb_xg*500+50, alpha=.7,
c=equipo2_color,
ax=ax,
label="NGA tiros")
ax.legend(labelspacing=1.5)
Estoy seguro de que este tutorial será de gran ayuda para que puedas realizar visualizaciones de mapas de tiros de cualquier partido utilizando los datos abiertos de StatsBomb. Ayúdame a compartir este artículo para que llegue a más personas y sea de gran utilidad 🙂
El código utilizado lo puedes revisar y descargar desde mi repositorio de GitHub.