Python Intermedio para Fútbol

Módulo 5: Uniendo fuerzas - Combinando sets de datos

1. El informe completo del ojeador

A lo largo de este curso, hemos trabajado intensamente con un set de datos de eventos de un partido. Hemos aprendido a filtrarlo, a crear nuevas métricas y a agruparlo para obtener resúmenes. Pero si queremos hacer un análisis verdaderamente profesional, a menudo nos daremos cuenta de que a nuestros datos les falta contexto.

Imagina que eres un ojeador. No presentas un informe sobre un jugador diciendo solo “hizo 5 tiros”. Un informe completo incluiría también su posición en el campo, los minutos que jugó, su edad y su equipo. Toda esta información adicional no suele estar en el mismo archivo que los datos de eventos.

Aquí es donde entra una de las tareas más comunes y cruciales en el análisis de datos: combinar o unir diferentes fuentes de información. La idea es tomar dos o más tablas de datos y unirlas de forma inteligente para crear un único DataFrame mucho más completo y potente.

En este módulo final, aprenderás a usar las herramientas que Pandas nos ofrece para realizar estas uniones. Dominar esta habilidad te permitirá pasar de analizar un único aspecto del juego a construir una visión de 360 grados, que es lo que se espera de un analista en un entorno profesional.

2. La herramienta principal para unir datos: pd.merge()

Para unir o combinar dos DataFrames que comparten información en común, la función principal que usaremos es pd.merge(). Piensa en esta función como la encargada de buscar coincidencias entre dos listas y, cuando encuentra una, juntar la información de ambas en una sola fila.

Para que merge funcione, necesita una “clave” o una columna en común entre los dos DataFrames. El ejemplo más claro es una columna player_name. Si ambos DataFrames tienen esta columna, merge puede usarla para saber qué fila de la tabla A corresponde con qué fila de la tabla B.

Existen varios tipos de uniones, similares a las que se usan en bases de datos SQL. Por ahora, nos centraremos en entender las dos más comunes:

  • Inner Join (Unión Interna): Este es el comportamiento por defecto. Al unir dos tablas, el resultado final solo contendrá las filas donde la clave (por ejemplo, el nombre del jugador) exista en ambas tablas. Si un jugador está en la primera tabla pero no en la segunda, será descartado. Es la intersección de ambos conjuntos.

  • Left Join (Unión Izquierda): En este caso, el resultado mantendrá todas las filas de la tabla de la izquierda (la primera que pasamos a la función) y buscará las coincidencias en la tabla de la derecha. Si un jugador de la tabla izquierda no tiene una coincidencia en la derecha, sus nuevas columnas se rellenarán con valores nulos (NaN), pero no será eliminado.

La elección entre un tipo de unión u otro depende de la pregunta que quieras responder. ¿Solo te interesan los jugadores que aparecen en ambos sets de datos, o quieres mantener toda tu lista original y simplemente enriquecerla con la información que esté disponible?

En la siguiente sección, veremos un caso práctico de cómo usar pd.merge() para enriquecer nuestros datos de eventos de un partido.

3. Caso práctico: enriqueciendo los datos de un partido

Vamos a realizar una de las uniones más comunes en el análisis de fútbol: añadir la posición de cada jugador a nuestro DataFrame de eventos. Esto nos permitirá, por ejemplo, filtrar todos los pases hechos únicamente por los mediocampistas.

Primero, en nuestro Jupyter Notebook, necesitamos dos DataFrames:

  1. match_data: El DataFrame con todos los eventos del partido, que ya sabemos cómo cargar.
  2. df_jugadores: Un nuevo DataFrame simple que crearemos manualmente con el nombre y la posición de algunos jugadores del Liverpool.

Paso 1: Crear nuestros DataFrames

En una celda de tu notebook, prepara los datos:

import pandas as pd
from underdata import Understat

# Obtenemos los datos del partido
epl = Understat(league="EPL")
match_data = epl.get_match_data(match_id=23722)

# Creamos nuestro segundo DataFrame con la información de los jugadores
datos_jugadores = {
    'player': ['Virgil van Dijk', 'Trent Alexander-Arnold', 'Alexis Mac Allister', 'Mohamed Salah', 'Darwin Núñez'],
    'posicion': ['Defensa', 'Defensa', 'Mediocentro', 'Delantero', 'Delantero']
}
df_jugadores = pd.DataFrame(datos_jugadores)

print("--- DataFrame de Jugadores ---")
print(df_jugadores)

Paso 2: Unir los DataFrames con pd.merge()

Ahora, usaremos pd.merge() para unir match_data (nuestra tabla de la izquierda) con df_jugadores (nuestra tabla de la derecha). La columna que tienen en común es player, por lo que Pandas la usará automáticamente como la clave para hacer la unión.

# Unimos los dos DataFrames
# Pandas detecta automáticamente que la columna 'player' es la clave en común
match_data_enriquecido = pd.merge(match_data, df_jugadores, on='player', how='left')

Analicemos los parámetros que usamos:

  • match_data, df_jugadores: Las dos tablas que queremos unir.
  • on='player': Le indicamos explícitamente que la columna player es la clave para la unión.
  • how='left': Usamos una “unión izquierda”. Esto es importante. Significa que mantendremos todos los eventos del match_data original. Si un jugador en match_data no está en nuestra lista de df_jugadores, su nueva columna posicion simplemente contendrá un valor nulo (NaN), pero la fila no será eliminada.

Paso 3: Verificar el resultado

Vamos a ver cómo se ve nuestro nuevo DataFrame enriquecido.

# Mostramos las primeras filas con las columnas relevantes
print("\n--- DataFrame Enriquecido ---")
print(match_data_enriquecido[['player', 'posicion', 'result']].head())

Ahora, cada evento tiene asociada la posición del jugador que lo realizó. Esto nos abre un nuevo mundo de posibilidades de análisis. Por ejemplo, podríamos filtrar fácilmente todos los pases hechos por los ‘Mediocentros’.

En la siguiente sección, aprenderemos sobre otro método de combinación, pd.concat(), que en lugar de unir tablas por los lados, nos permite apilarlas una encima de la otra.

4. Apilando datos con pd.concat()

Mientras que pd.merge() es perfecto para unir DataFrames basándose en columnas en común (unión horizontal), a veces nos enfrentamos a un problema diferente: tenemos varios DataFrames con la misma estructura de columnas y queremos simplemente juntarlos en una única tabla, uno debajo del otro.

Piensa en esta situación: un proveedor de datos te entrega los eventos de un partido, pero en dos archivos separados, uno para la primera mitad y otro para la segunda. Para analizar el partido completo, necesitas unirlos. La herramienta para esta tarea es pd.concat().

La diferencia es clave:

  • merge: Une por los lados, basándose en una clave.
  • concat: Apila por arriba y por abajo, asumiendo que las columnas coinciden.

Caso práctico: uniendo las dos mitades de un partido

Vamos a simular que tenemos dos DataFrames. Uno con los eventos de la primera mitad y otro con los de la segunda.

# Asumimos que 'match_data' está cargado con el partido completo

# 1. Simulamos los dos DataFrames separados
primera_mitad = match_data[match_data['minute'] <= 45]
segunda_mitad = match_data[match_data['minute'] > 45]

print(f"Eventos en la primera mitad: {len(primera_mitad)}")
print(f"Eventos en la segunda mitad: {len(segunda_mitad)}")

# 2. Creamos una lista que contiene los DataFrames que queremos apilar
dataframes_a_unir = [primera_mitad, segunda_mitad]

# 3. Usamos pd.concat() para unirlos
partido_completo = pd.concat(dataframes_a_unir)

print(f"Total de eventos en el DataFrame unido: {len(partido_completo)}")

La función pd.concat() toma una lista de DataFrames y los concatena en el orden en que aparecen. Es una operación directa y muy eficiente.

Un parámetro útil es ignore_index=True. Si los índices de tus DataFrames originales se repiten (por ejemplo, ambos van de 0 a 1000), al unirlos, tendrás índices duplicados. ignore_index=True soluciona esto, creando un nuevo índice continuo para el DataFrame final.

partido_completo = pd.concat(dataframes_a_unir, ignore_index=True)

Con pd.merge() y pd.concat(), ya tienes las dos herramientas principales para combinar datos en casi cualquier escenario que te encuentres como analista. En la sección final, haremos un resumen de todo lo que hemos logrado en este curso intermedio.

5. Conclusiones y cierre del curso intermedio

Has llegado al final de esta formación y has completado un recorrido fundamental en el mundo del análisis de datos. Si miramos atrás, el camino ha sido transformador:

  • Empezamos aprendiendo a explorar un set de datos para entender su estructura.
  • Luego, dominamos el filtrado para aislar la información precisa que necesitábamos.
  • Dimos un salto cualitativo al crear nuestras propias métricas, enriqueciendo los datos crudos.
  • Aprendimos a agrupar la información para pasar del análisis de jugadas individuales a patrones de equipo.
  • Y finalmente, en este módulo, has aprendido a combinar diferentes fuentes de datos, una habilidad esencial para construir una visión completa y profesional.

Con estas herramientas, ya no solo lees datos; eres capaz de manipularlos, transformarlos y prepararlos para un análisis profundo. Tienes un dominio sólido de la librería Pandas, que es el corazón del día a día de cualquier analista de datos.

La próxima temporada: la formación avanzada

Hemos preparado el terreno a la perfección. Ahora que sabes cómo manejar los datos, el siguiente paso es hacerlos hablar. En la siguiente formación gratuita, daremos el paso más visual y gratificante. Dejaremos atrás la manipulación de datos y empezaremos a dibujar en el lienzo. Aprenderás a:

  • Crear gráficos básicos pero potentes (barras, scatter, etc.) para comparar jugadores y equipos.
  • Construir tus primeras visualizaciones específicas del fútbol: graficaremos una cancha, crearemos un mapa de tiros y diseñaremos una red de pases.

¡Felicidades por completar este curso y prepárate para lo que viene!