"""MP1 · paso 15: comparador B2 (pre-registro §6): el modelo de E1 (variante B) y el de E1c (misma receta con la etiqueta cambiada: 1 desierto, 2 adjudicado, como e1c/py/01_medida.py), entrenados con sus propios lotes de anuncio 2016-2025 y aplicados a los lotes anunciados en 2026. Código: /app = / (main b4519bd), solo lectura. Uso: python3 15_e1_comparador.py ou|des -> /w/interno/b2_.csv (licitacion_id, lote_u, p_b2) """ import sys, json, time, datetime as dt from pathlib import Path sys.path.insert(0, "/app") from etl.v2 import exante_l1 as e1 H = sys.argv[1]; assert H in ("ou", "des") T0 = time.time() U = Path("/d/unified_20261025") TMP = Path("/w/tmp/duck"); TMP.mkdir(parents=True, exist_ok=True) con = e1.conexion(memoria="8GB", hilos=6, temporal=TMP) e1.paso_entrada(con, U, Path(f"{U}.identidad"), Path(f"{U}.criterios"), Path(f"{U}.documentos"), Path(f"{U}.cpvs")) e1.paso_lotes(con) if H == "des": con.execute("UPDATE x_lotes SET num_ofertas = CASE WHEN adjudicado THEN 2 WHEN desierto THEN 1 ELSE NULL END") e1.paso_historial(con) # fecha de corte 2027-01-01: los lotes anunciados en 2026 entran como «historico» (anio 2026) y se pueden predecir e1.paso_objetos(con, dt.date(2027, 1, 1), None) e1.paso_dataset(con) aj = e1.ajustar(con, "B", "conjunto = 'historico' AND anio BETWEEN 2016 AND 2025", anios=tuple(range(2016, 2026))) e1.predecir(con, aj, "conjunto = 'historico' AND anio = 2026", "x_pred_t") con.execute(f"""COPY (SELECT o.licitacion_id, o.lote_u, p.p AS p_b2 FROM x_pred_t p JOIN x_obj o USING (oid) ORDER BY 1, 2) TO '/w/interno/b2_{H}.csv' (HEADER, DELIMITER ',')""") n = con.execute("SELECT count(*) FROM x_pred_t").fetchone()[0] json.dump({"desenlace": H, "n_2026": n, "iteraciones": aj.iteraciones, "n_entrenamiento": aj.n, "p0": aj.p0, "segundos": round(time.time() - T0, 1)}, open(f"/w/salidas/15_b2_{H}.json", "w"), indent=1) print("ok", H, n, round(time.time() - T0, 1), "s", flush=True)