File size: 5,799 Bytes
31157f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python3
"""Sincroniza el diccionario de variables que manda el club con nuestros metadatos.

El club manda un xlsx con cuatro columnas: ``Categoría`` (categoría de estilo de juego),
``Categoria_2`` (subcategoría), ``Nombre`` (nombre de uso) y ``Nombre Columna`` (nombre en el
dataset). Este script lo compara con lo que tenemos y actualiza:

  scripts/feature_groups.json ....... agrega (nunca borra) las variables que el club asigna a
                                      una categoría y a nosotros nos faltaba el grupo
  scripts/feature_subgroups.json .... columna → subcategoría (``Categoria_2``), info nueva
  scripts/var_labels_extra.json ..... se poda: quedan solo los nombres que el club NO da

Después hay que re-correr, en este orden:
  python scripts/build_var_dict.py
  python webapp-static/build_data.py
  python scripts/gen_diccionario_variables.py
  python scripts/gen_referencia.py

El xlsx **no está versionado** (`*.xlsx` está en .gitignore porque el repo es público):
guardá el que manda el club en la raíz de racing-reports/ antes de correr esto.

Uso:  python scripts/sync_club_dictionary.py [ruta.xlsx] [--dry-run]
"""
from __future__ import annotations

import json
import sys
from pathlib import Path

import pandas as pd

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from racing_reports import team_vars  # noqa: E402

DEFAULT_XLSX = ROOT / "diccionario_variables_2.xlsx"
GROUPS = ROOT / "scripts" / "feature_groups.json"
SUBGROUPS = ROOT / "scripts" / "feature_subgroups.json"
EXTRA = ROOT / "scripts" / "var_labels_extra.json"

# Categoría del club → nombre del grupo tal como se ve en la app.
CAT_TO_GRUPO = {
    "Balón Parado": "Balón parado",
    "Balón Parado – Defensivo": "Balón parado (rival)",
    "Build-up / Posesión": "Build-up / Posesión",
    "Defensiva": "Defensiva",
    "Defensiva – Presión": "Defensiva – Presión",
    "Disciplina / Control": "Disciplina / Control",
    "Ofensiva – Creación": "Ofensiva – Creación",
    "Transiciones – Defensivas": "Transiciones – Defensivas",
    "Transiciones – Ofensivas": "Transiciones – Ofensivas",
    # ESTRATEGIA (formacion / formacion_rival) no entra: no son métricas, van como metadato.
}


def main() -> None:
    args = [a for a in sys.argv[1:] if not a.startswith("--")]
    dry = "--dry-run" in sys.argv
    xlsx = Path(args[0]) if args else DEFAULT_XLSX
    dic = pd.read_excel(xlsx, sheet_name=0)
    dic["col"] = dic["Nombre Columna"].astype(str).str.strip().str.lower()
    dic = dic.rename(columns={"Categoría": "cat", "Categoria_2": "sub", "Nombre": "nombre"})

    nuestras = {c.lower() for c in team_vars.variables()}
    groups = json.loads(GROUPS.read_text(encoding="utf-8")) if GROUPS.exists() else {}
    extra = json.loads(EXTRA.read_text(encoding="utf-8")) if EXTRA.exists() else {}

    print(f"[sync] {xlsx.name}: {len(dic)} filas · nuestras variables: {len(nuestras)}")

    fuera = dic[~dic["col"].isin(nuestras)]
    if len(fuera):
        print(f"\n  {len(fuera)} variables del club que NO existen en team_stats_agg:")
        for r in fuera.itertuples():
            print(f"    {r.col:32} ({r.nombre})")

    # ── grupos: unión ─────────────────────────────────────────────────────────
    add, nuevos_grupos = 0, set()
    for r in dic[dic["col"].isin(nuestras)].itertuples():
        g = CAT_TO_GRUPO.get(str(r.cat).strip())
        if not g:
            continue
        cur = groups.setdefault(r.col, [])
        if g not in cur:
            cur.append(g)
            cur.sort()
            add += 1
            if g not in {x for v in groups.values() for x in v if v is not cur}:
                nuevos_grupos.add(g)
    sin_grupo = sorted(c for c in nuestras if not groups.get(c))
    print(f"\n  grupos agregados: {add}")
    print(f"  variables sin ningún grupo: {len(sin_grupo)}"
          + (f" → {sin_grupo}" if sin_grupo else ""))
    por_grupo = {}
    for c, gs in groups.items():
        for g in gs:
            por_grupo[g] = por_grupo.get(g, 0) + 1
    print("  grupos resultantes:")
    for g in sorted(por_grupo):
        print(f"    {g:34} {por_grupo[g]:3}")

    # ── subcategorías ─────────────────────────────────────────────────────────
    subs = {r.col: str(r.sub).strip()
            for r in dic[dic["col"].isin(nuestras)].itertuples()}
    print(f"\n  subcategorías (Categoria_2): {len(subs)} variables · "
          f"{len(set(subs.values()))} valores distintos")

    # ── labels: podar var_labels_extra ────────────────────────────────────────
    nombrados = set(dic["col"])
    sobran = sorted(k for k in extra if k.lower() in nombrados)
    quedan = {k: v for k, v in extra.items() if k.lower() not in nombrados}
    print(f"\n  var_labels_extra: {len(extra)} → {len(quedan)} "
          f"({len(sobran)} ya los nombra el club)")
    if quedan:
        print(f"    quedan a mano: {sorted(quedan)}")

    if dry:
        print("\n[sync] --dry-run: no se escribió nada")
        return
    GROUPS.write_text(json.dumps(groups, ensure_ascii=False, indent=1), encoding="utf-8")
    SUBGROUPS.write_text(json.dumps(dict(sorted(subs.items())), ensure_ascii=False, indent=1),
                         encoding="utf-8")
    EXTRA.write_text(json.dumps(quedan, ensure_ascii=False, indent=1), encoding="utf-8")
    print(f"\n[sync] escrito: {GROUPS.name}, {SUBGROUPS.name}, {EXTRA.name}")


if __name__ == "__main__":
    main()