MUNDIAL 2026 · PROYECTO DE ANÁLISIS DE DATOS
Análisis de datos · Power BI · Python · SQL

Mundial 2026

Datos, goles y negocio: el primer Mundial de 48 equipos

104
partidos analizados
48
selecciones
16
sedes
6
páginas de dashboard
Índice

Contenido de la presentación

Hacé clic en cualquier ítem para ir directo

  • 01Objetivo del proyecto
  • 02Proceso
  • 03Calidad de datos
  • 04Python: la limpieza en código
  • 05SQL: el esquema
  • 06SQL: la vista en código
  • 07Modelo de datos en Power BI
  • 08DAX: medidas clave
  • 09Todas las medidas
  • 10Dashboard: Portada
  • 11Dashboard: Resumen
  • 12Dashboard: Equipos
  • 13Dashboard: Jugadores
  • 14Dashboard: Tarjetas
  • 15Dashboard: Negocio
  • 16Hallazgo de negocio
  • 17Conclusiones
  • 18Cierre
01 · Objetivo del proyecto

Un proyecto de punta a punta, no solo un dashboard

Pensado para mostrar el ciclo completo de un análisis de datos real

  • Obtención y limpieza de datos crudos con Python
  • Modelado relacional en PostgreSQL, con vistas en vez de datos duplicados
  • Dashboard interactivo en Power BI, con identidad visual propia
  • Lectura de negocio sobre los datos, no solo estadística deportiva

El objetivo no era solo "hacer un dashboard de fútbol" — fue construir un proyecto que muestre las dos caras de mi perfil: Data Analyst y Business Analyst, con el rigor de datos de una y la mirada de negocio de la otra.

02 · Proceso

De datos crudos a dashboard, en 4 etapas

01
Obtención
Dataset de Kaggle: 12 tablas relacionales sobre el Mundial 2026 (partidos, jugadores, sedes, eventos).
02
Limpieza (Python)
Corrección de nombres, encoding roto, y reconstrucción de columnas de texto libre vía IDs.
03
Modelado (SQL)
Esquema normalizado en PostgreSQL, con una vista en vez de duplicar tablas desnormalizadas.
04
Dashboard (Power BI)
6 páginas con identidad visual propia, DAX a medida, y foco en negocio además de estadística.
03 · Calidad de datos

Los datos "de Kaggle" no vienen listos para usar

Encontrar y documentar los problemas es tan parte del análisis como resolverlos

Tildes y ñ faltantes
Apellidos hispanos/portugueses llegaron sin su acento correcto — Quinones → Quiñones. Se corrigió con un diccionario de ~30 apellidos comunes.
Encoding roto (mojibake)
Letras checas, turcas y polacas (š, ě, ğ, ł) aparecían con espacios insertados. Se verificaron y corrigieron 13 nombres contra fuentes públicas reales.
Nombres mal armados
13 jugadores (Brasil, Portugal, Cabo Verde, Qatar) con el apellido pegado en mayúsculas: MARQUINHOSMarcos → Marquinhos.
Limitación documentada, no escondida
7 jugadores con apellido truncado a "Mc" (McGinn, McTominay) que no se pudo reconstruir con los datos disponibles — documentado como tal, sin inventar el dato.
03b · Limpieza en código

Python: corrigiendo con reglas, no a mano

Un fragmento real de clean_data.py

# Diccionario de apellidos que llegaron sin su acento correcto
correcciones_apellidos = {
  "Nunez": "Núñez", "Munoz": "Muñoz", "Quinones": "Quiñones",
  "Hernandez": "Hernández", "Rodriguez": "Rodríguez",
  # ... ~30 apellidos hispanos/portugueses comunes
}

def corregir_apellido(nombre):
  for mal_escrito, correcto in correcciones_apellidos.items():
    nombre = re.sub(rf"\b{mal_escrito}\b", correcto, nombre)
  return nombre
Además de esto: corrección de 13 casos de encoding roto (mojibake checo/turco/croata) verificados contra fuentes públicas, y reconstrucción de columnas de texto libre usando joins por ID en vez de confiar en el texto original.
04 · Modelo de datos

PostgreSQL: normalizado, sin datos duplicados

  • 10 tablas + 1 vista, en vez de cargar tablas ya "desnormalizadas" de la fuente original
  • La vista matches_detailed_view reconstruye los datos con nombres, vía JOIN, sin duplicar información
  • Relaciones con foreign keys, respetando integridad referencial

Un aprendizaje del camino: al calcular "valor de plantel vs. goles por equipo" en una sola query, el primer intento infló los goles varias veces — un clásico error de fan-out al mezclar tablas de distinta granularidad en el mismo JOIN. Se resolvió separando el cálculo en subconsultas independientes antes de unir los resultados agregados.

04b · Modelo en código

SQL: una vista en vez de duplicar datos

Un fragmento real de schema.sql

CREATE VIEW matches_detailed_view AS
SELECT
  m.match_id, m.match_date, st.stage_name,
  ht.team_name AS home_team_name,
  at.team_name AS away_team_name,
  v.stadium_name, r.name AS referee_name
FROM matches m
JOIN tournament_stages st ON m.stage_id = st.stage_id
JOIN teams ht ON m.home_team_id = ht.team_id
JOIN teams at ON m.away_team_id = at.team_id
JOIN venues v ON m.venue_id = v.venue_id
JOIN referees r ON m.referee_id = r.referee_id;
En vez de cargar matches_detailed.csv tal cual (que duplicaba la información de matches con los nombres ya resueltos), esta vista arma el mismo resultado al vuelo, sin guardar el dato dos veces.
04c · Power BI · Modelo de datos

Las relaciones detrás del dashboard

10 tablas conectadas por sus claves · la relación matches ↔ teams se activa puntualmente con USERELATIONSHIP · las medidas viven aparte, en _Medidas

Captura: vista de Modelo en Power BIimg/07_modelo.png
04d · Power BI · DAX

Algunas medidas clave

Goles a Favor =
  CALCULATE(
    SUMX(matches, matches[home_score]),
    USERELATIONSHIP(matches[home_team_id], teams[team_id])
  ) + /* + análogo para visitante */

Periodo del Gol =
  SWITCH(TRUE(),
    minuto_limpio <= 45, "Primer tiempo",
    minuto_limpio <= 90, "Segundo tiempo",
    minuto_limpio <= 120, "Alargue", "Otro"
  )

Partidos con Penales =
  COUNTROWS(FILTER(matches, NOT ISBLANK(matches[home_penalty_score])))
La primera resuelve un desafío del modelo: la relación entre partidos y equipos está inactiva por diseño (para evitar rutas ambiguas), así que se activa puntualmente donde hace falta. La segunda clasifica cada gol por período, limpiando primero el minuto de descuento (ej. "90+2"). La tercera es un patrón simple: contar filas que cumplen una condición.
04e · Power BI · DAX

27 medidas, todas en un solo lugar

La tabla _Medidas, separada de los datos crudos

  • Arbitros Distintos
  • Capacidad Sedes (texto)
  • Capacidad Total Sedes
  • Goles a Favor
  • Goles Acumulados
  • Goles en Contra
  • Goles por Fase (Jugador)
  • Goles por Millon
  • Goles Promedio por Partido
  • Goles Totales
  • Partidos con Expulsion
  • Partidos con Penales
  • Partidos Empatados
  • Partidos Ganados
  • Partidos Perdidos
  • Posesion Promedio
  • Tarjetas Jugador
  • Tarjetas por Fase
  • Tarjetas por Partido
  • Total Amarillas
  • Total Paises Sede
  • Total Partidos
  • Total Rojas
  • Total Sedes
  • Total Selecciones
  • Total Tarjetas
  • Valor Plantel Total
Dashboard · Página 1 de 6

Portada

Presentación del proyecto, con los números clave del torneo a modo de "hook" visual y el stack técnico usado.

Captura: página Portadaimg/01_portada.png
Dashboard · Página 2 de 6

Resumen del torneo

  • Goles por fase, con evolución a lo largo del torneo
  • Mapa de sedes (tamaño = goles jugados en esa sede)
  • Distribución de goles por período (1T, 2T, alargue)
Captura: página Resumenimg/02_resumen.png
Dashboard · Página 3 de 6

Equipos

  • Ganados / empatados / perdidos por selección
  • Goles a favor vs. en contra
  • Goles por confederación (treemap)
  • Posesión promedio por equipo
Captura: página Equiposimg/03_equipos.png
Dashboard · Página 4 de 6

Jugadores

  • Goleadores y asistidores del torneo
  • Jugadores más amonestados/expulsados
  • Evolución de los goleadores por fase
Captura: página Jugadoresimg/04_jugadores.png
Dashboard · Página 5 de 6

Tarjetas

  • Total de amarillas, rojas y partidos con expulsión
  • Equipos con más tarjetas
  • Tarjetas por fase y su evolución en el tiempo
Captura: página Tarjetasimg/05_tarjetas.png
Dashboard · Página 6 de 6

Negocio

  • Valor de plantel vs. goles convertidos
  • Mapa mundial de goles por país
  • Partidos por confederación y país sede
  • Partidos con más goles del torneo
Captura: página Negocioimg/06_negocio.png
05 · Hallazgo de negocio

Europa dominó el mapa de goles del torneo

45%
de todos los goles del torneo fueron convertidos por selecciones de UEFA
UEFA concentró 151 de los 335 goles del Mundial, casi el doble en promedio por equipo (9.4) que CONMEBOL, la segunda confederación más goleadora (7.0). Francia e Inglaterra empataron como máximos goleadores del torneo con 20 goles cada uno; Argentina fue la única selección no europea en el podio, con 19.
ConfederaciónGoles totalesGoles / equipo
UEFA1519.4
CONMEBOL427.0
CONCACAF335.5
CAF535.3
AFC252.8
06 · Conclusiones

Lo que deja este proyecto

01
Los datos "de fuente" casi nunca están listos
Documentar y corregir problemas de calidad con criterio es tan valioso como el análisis final.
02
SQL bien pensado ahorra trabajo en Power BI
Decidir qué se resuelve en la base y qué en DAX evita duplicar lógica y datos.
03
Un dashboard también es una decisión de diseño
Identidad visual propia, navegación consistente y jerarquía clara — no solo gráficos correctos.
04
Mirar los datos desde negocio, no solo desde el dato
Cruzar valor de plantel, geografía y rendimiento agrega una lectura que el fanatismo futbolero no da.
Gracias

Mundial 2026: un proyecto de punta a punta

Data cleaning · SQL · Power BI · Business Analysis