Spaces:
Running
Running
Commit History
-
Top equipos: variables por lado, y "Defensa" se fusiona en "Defensiva"
El selector era una fila plana de 23 chips de grupo, con "Defensa" y "Defensiva" compitiendo por el mismo concepto. Ahora: - "Defensa" y "Defensa (rival)" se fusionan en "Defensiva" (21 grupos, era 23). scripts/style_clash/build_clusters.py pasa a usar el nombre nuevo. - var_dict expone `lado` (propia / rival). La regla es el sufijo `_rival` / `_against`, con cuatro excepciones revisadas: recuperaciones_campo_rival, altura_media_recuperacion_campo_rival, su desviación y faltas_a_favor_rival ("Faltas Cometidas"), donde "rival" nombra la mitad de cancha, no al que actúa. Quedan 164 propias y 98 del rival. - El picker son dos desplegables —propias y del rival— con los temas adentro. Los grupos "X (rival)" dejan de ser un grupo aparte: son la cara rival del mismo tema. Heatmap de Top equipos: hasta 50 equipos, scroll libre con encabezado y equipo fijos, y una columna # con la posición en el puntaje general que NO se mueve al ordenar por una variable. clasica.html no cambia: …307ee85
-
Integrar el diccionario de variables del club
El club manda su diccionario con cuatro columnas (Categoría, Categoria_2, Nombre, Nombre Columna). La versión de septiembre nombra las 262 variables de team_stats_agg; la que leíamos hasta ahora tenía 174, y por eso 95 nombres vivían a mano en var_labels_extra.json y 56 variables quedaban sin categoría. - scripts/sync_club_dictionary.py: integra el xlsx y es re-corrible. Agrega, nunca borra: suma las categorías del club a feature_groups.json sin tocar nuestros grupos propios (Centros, Presión, Verticalidad, Rotura de líneas), escribe feature_subgroups.json con el segundo nivel y poda var_labels_extra.json. - 0 variables sin grupo (eran 56) y grupo nuevo Disciplina / Control. Build-up 30→50, Defensiva 42→63, Defensiva–Presión 20→43, Ofensiva–Creación 45→67. - Subcategoría (Categoria_2, 19 valores) como segundo nivel: columna nueva en variables.csv, cuadro por subcategoría en los .md y fila en la ficha de la referencia. - build_var_dict.py lee el xlsx del repo y expone subgrup…31157f4
-
Las features de train, listadas de verdad en cada modelo
Los cuadros de "Features" decían solo "self_* (forma del equipo)". Ahora traen la lista completa, leída de los artefactos reales: - cruce: las 328 de matchup_feat_cols.json, separadas por prefijo — self_ (53), opp_ (157), selfH_ (52) y selfA_ (52) que son el split local/visitante, y 14 de contexto (elo, is_*, form*) - ptiro: las 72 de datasets_variables.json - los dos GNN: leídas del bundle .pt (global_bundle.global_feature_columns) De paso, los .pt traen el summary con los tamaños reales del split, que estaban sin documentar: ataque 8.506/962/1.108 (validación desde el 16-nov-2025, 5 semillas) y peligro 7.395/842/981 (desde el 17-nov-2025). CORRECCIÓN: pv_distribution_gnn NO poda features — usa las 1.069 globales, mientras que el de ataque se queda con 200. Estaba documentado como si compartieran el criterio. Con el mismo dataset (~10.900 filas) eso le deja una proporción features/filas mucho más exigente; queda anotado como candidato a aplicarle la misma poda y medir. Co-Auth…6a437ee -
La referencia muestra la ficha completa, y "?" en todos los reportes
Al tocar el "?" ahora se ve toda la documentación del gráfico o modelo, no solo el resumen: cómo se entrena, con qué datos, qué variables usa, qué devuelve y cuánto le saca al baseline. - gen_referencia.py convierte el .md entero a HTML (headings, tablas, listas, citas, código) y lo embebe como "La ficha completa" de cada sección - "?" también en los reportes por equipo del Space (bloques, multi-tag, centros, recuperaciones), armado desde rep.id - pv_distribution_gnn estaba documentado apenas como "el complemento del otro"; ahora tiene su ficha propia leída del código: arquitectura de grafo sobre las 10 zonas, cabezas gate+delta (aprende la corrección sobre un baseline, no el valor directo), split temporal, estandarización solo sobre train, 260 épocas con early stopping Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>f387940
-
Sección 'Recursos bloque bajo': scatter interactivo + tablas por equipo
Scatter con liga (opción todas), ejes configurables (lado of/def × recurso × métrica: pv/jugada, tiros/jugada, xG acum/por jugada/por exitosa, goles, %goles, %éxito, intentos), hover con equipo, click fija etiqueta. Abajo: tablas ofensiva y defensiva por equipo con media de liga. Artefacto vendor/data/lowblock/ (mín 10 intentos por celda en scatter). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>b3df273
-
Ejes de ataque: reportes pre/post partido + scatter equipos + artefactos 28 ligas
- reports/ejes.py: ejes_pre (predicción por eje vs norma, gen propia × concesión rival) y ejes_post (firma del partido: ejes vs norma, esperado-vs-real del modelo, variables que más se movieron) - ejes_data.py: acceso a artefactos (dev dir → bundle vendor/data/ejes → Azure) - API /api/ejes/{options,profiles} + sección 5 'Ejes ataque/defensa' (scatter SVG interactivo) en Equipos y variables - artefactos bundleados: 28 ligas 25-26, modelo global AUC 0.98, validación predictor: acierto direccional 58% (63.8% en flechas grandes) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>a798829
-
Predicción de cruce en reporte pre-partido: bloque defensivo + pasillo de ataque + xT
Agrega modelos LightGBM (bloque defensivo, pasillo de ataque, xT por pasillo) al reporte pre-partido: para A y B dibuja la cancha de ataque por pasillos y la de bloque defensivo (bajo/medio/alto) + un insight del cruce. Inferencia con features rolling 'a la fecha' precalculadas. No rompe el reporte si faltan datos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>01fdb49
-
Variables negativas (menos=mejor): "mejor de la liga" = z más bajo + radar invertido
48 variables marcadas como negativas (rival/en contra/concedidas + errores/pérdidas/ tarjetas/ppda), revisadas una por una (excluye _rival neutrales de estilo y las buenas para nosotros como rojas del rival / faltas sufridas). En el diccionario se agrega el flag "negativa". - team_profile: para negativas, "mejor de la liga" = MÍNIMO (z más bajo). Item trae negativa. - radar: best=mín en negativas y usa lower_is_better de mplsoccer → "más afuera = mejor" en todos los ejes (los negativos se invierten). - Frontend: badge "↓" en las variables negativas del perfil. - variables_info expone negativa. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>cf1e649 -
Equipos y variables: nombres lindos del diccionario + selección por tipo
- Diccionario (diccionario_variables.xlsx → vendor/data/var_dict.json vía scripts/build_var_dict.py): mapea columna → nombre legible + tipo. Si una columna no está en el diccionario, se deja su nombre crudo (tipo "Otras"). - Las variables se muestran/buscan por su nombre lindo (datalist por label); el front mapea label→columna al enviar. Resultados de búsqueda/perfil y labels del radar usan el nombre lindo. - Selección rápida por TIPO: botones (Ofensiva, Defensiva, Build-up/Posesión, Balón Parado, Transiciones, Disciplina/Control, Estrategia) que agregan todas las variables de ese tipo, tanto en la búsqueda como en el perfil. - /options ahora devuelve variables [{name,label,tipo}] y types {tipo:[cols]}. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>e672925
-
team_stats agg: matchid como str (fix de duplicados no colapsados)
matchid tiene valores numéricos (131k) y alfanuméricos (65k). Al leer por chunks, pandas inferenciaba el tipo por chunk → el mismo matchid numérico quedaba int en un chunk y str en otro → no agrupaban → las 2 versiones del equipo-partido NO se colapsaban en ligas con matchid numérico (EPL, La Liga, etc.), inflando n_partidos (~150k→101k) y metiendo la versión espuria en los promedios. Fix: leer matchid y temporada como str. Ahora cada liga da el conteo real (EPL/La Liga = 38 por equipo) y una sola versión consistente por equipo-partido. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>d290f9e -
team_stats agg: elegir la versión consistente del duplicado (posesión vs dominio de pases)
Cada equipo-partido aparece con 2 versiones (conteos idénticos pero posesión y derivadas distintas; una está mal: p.ej. 73% de posesión con menos pases que el rival). En vez de dedup arbitrario, por (equipo, partido) se elige la versión cuya posesión es coherente con el dominio de pases (más pases que el rival → >50%). Efecto: la posesión por liga ahora centra en ~50% (antes una versión espuria inflaba/distorsionaba). Conteos sin cambio. Regenera vendor/data/team_stats_agg.parquet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1ada03e -
Nueva sección "Equipos y variables": buscar equipos por z-score de variables
Sobre team_stats_all_leagues.csv (stats por partido/equipo de Azure), agregado a un perfil por (liga, temporada, equipo) = promedio por partido. El usuario elige variables y dirección (alto/medio/bajo); se calcula un z-score por variable dentro del pool (liga+temporada, mín. 5 partidos) y un puntaje: alto → z ; bajo → -z ; medio → -|z|. Suma por equipo → top 5 con desglose por variable (valor, z, puntaje). - scripts/build_team_stats_agg.py: baja el CSV (~870 MB), filtra estado "90 mins" (total del partido) + dedup por matchid, agrega → vendor/data/team_stats_agg.parquet (3.8 MB, bundleado; regenerable como matches_catalog). - team_vars.py: carga el agregado + scoring; routes_team_vars.py: /api/team-vars/{options,search}. - home.html: tab "Equipos y variables" (selección de variables + dirección + top 5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>d1858cc
-
Todas las ligas Opta en los selectores + default Spanish Segunda
- build_matches_catalog.py: arma un catálogo (liga/temporada/fecha/local/visitante) desde los NOMBRES de los xlsx en Azure (listar es barato, no descarga). Cubre 27 ligas Opta. Bundleado en vendor/data/matches_catalog.parquet (60KB). - web_meta usa el catálogo para ligas/temporadas/equipos/partidos (todas las ligas) y el dataset del modelo solo para el matchId real (post-partido / 9 ligas). - routes_meta: leagues() pone Spanish Segunda Division primero; el resto sale del catálogo ∩ preprocessed disponible -> 26 ligas. Default = SSD 25-26. - Los reportes descriptivos (bloques/multitag/centros/recuperaciones) andan para cualquier liga con preprocessed; post-partido+predicción siguen en las del modelo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>5012a96
-
Deploy MVP: API JSON + SPA + bundle/cache de artifacts CORE
Sprint 1 + 2: - API JSON (/api/health, /api/leagues, /api/teams, /api/matches, /api/reports/{type}/{catalog,run}, /api/jobs/{id} + figure/table/html/zip). - ReportBundle: figuras como PNG+SVG y tablas como CSV, individuales. - SPA en / (Tailwind + Alpine, sin build) que consume /api/. - HTML legacy disponible en /legacy. - block_zscore con fallback a phaseLabel cuando no hay labeled CSV en Azure. - pre_match con predicciones NN deshabilitadas (placeholder) cuando los .pt no estan disponibles. Reactivable con RR_ENABLE_NN_PREDICTIONS=1. - post_match deshabilitado en MVP (depende del NN). Reactivable junto al flag. - Artifacts CORE (match_features + team_match_zone_features, ~4 MB) bundleados en vendor/data/ para no requerir upload manual a Azure.e58615a