"""E8 · veredicto por mercado con los umbrales sellados (§7) y salidas publicables (§5). Sin red. Lee las salidas de las dos implementaciones y los cotejos juzgados a mano. Escribe salidas/e8_veredicto.json, salidas/publicable_mercado_anio.csv, salidas/publicable_organo.csv (solo mercados que PASAN; N ≥ 10; sin NIF de persona física; nunca empresas) y salidas/para_registro_precision.json (propuesta: NO se edita el registro).""" import json, csv, collections R = json.load(open('/p/salidas/e8_resumen_impl1.json')) I2 = json.load(open('/p/salidas/e8_impl2.json')) O = list(csv.DictReader(open('/p/salidas/e8_organos_impl1.csv'))) MD5 = open('/p/DEFINICIONES_PREVIAS_E8.md5').read().split()[0] ver = {} for m in ('carburantes', 'electricidad', 'papel'): r = R[m]; t = r['todos']; c = list(csv.DictReader(open(f'/p/priv/cotejo_{m}.csv'))) ok = sum(1 for x in c if x['juicio'] == 'correcto'); n = len(c); ok30 = sum(1 for x in c[:30] if x['juicio'] == 'correcto') v = {} v['1_cobertura'] = dict(valor=r['validos'], umbral='≥ 300', pasa=r['validos'] >= 300) v['2_cotejo'] = dict(valor=f'{ok}/{n}', primeros_30=f'{ok30}/{min(30, n)}', umbral='≥ 45/50 y ≥ 27/30 (con < 50, ≥ 90 %)', pasa=(ok >= 45 and ok30 >= 27) if n >= 50 else (n > 0 and ok / n >= 0.9)) d = I2[m]; dif_u, dif_v = d['pct_universo'], d['pct_validos'] org_ok = I2['organos']['pct_iguales'] >= 99.5 v['3_segunda_impl'] = dict(valor=dict(pct_universo=dif_u, pct_validos=dif_v, organos_iguales_pct=I2['organos']['pct_iguales']), umbral='≤ 0,5 % del universo y ≤ 1 % de los válidos; órganos ≥ 99,5 %', pasa=dif_u <= 0.5 and dif_v <= 1.0 and org_ok) if m == 'carburantes': rv = I2['referencia_carb_vs_wob'] v['4_referencia'] = dict(valor=f"{rv['dentro_3pct']}/{rv['meses_producto']} meses × producto dentro de ±3 % del WOB ({rv['pct']:.1f} %)", umbral='≥ 95 %', pasa=rv['pct'] >= 95) gc = r['por_producto'].get('gasoleo_c', {}) v['5_sentido'] = dict(valor=dict(mediana=t.get('mediana'), gasoleo_c_dentro_15=gc.get('pct_dentro_15')), umbral='mediana en [0,85; 1,15] y gasóleo C ≥ 75 % dentro de ±15 %', pasa=t.get('n', 0) > 0 and 0.85 <= t['mediana'] <= 1.15 and (gc.get('pct_dentro_15') or 0) >= 75) elif m == 'papel': g = r['grupo_referencia'] v['4_referencia'] = dict(valor=dict(n=g.get('n'), mediana=g.get('mediana'), dentro_085_110_pct=g.get('dentro_085_110_pct')), umbral='basados DGRCC: mediana en [0,90; 1,05] y ≥ 80 % en [0,85; 1,10]', pasa=bool(g.get('n')) and 0.90 <= g['mediana'] <= 1.05 and g['dentro_085_110_pct'] >= 80) v['5_sentido'] = dict(valor=None, umbral='sin umbral (lo valida el punto 4)', pasa=True) else: v['4_referencia'] = dict(valor='sin contraste independiente', umbral='no aplica', pasa=True) v['5_sentido'] = dict(valor=t.get('mediana'), umbral='mediana en [0,6; 1,5]', pasa=t.get('n', 0) > 0 and 0.6 <= t['mediana'] <= 1.5) fallan = [k for k, x in v.items() if not x['pasa']] ver[m] = dict(validaciones=v, veredicto='PASA' if not fallan else 'NO PASA', fallan=fallan) json.dump(ver, open('/p/salidas/e8_veredicto.json', 'w'), indent=1, ensure_ascii=False, default=str) # ---- publicables with open('/p/salidas/publicable_mercado_anio.csv', 'w', newline='') as fh: w = csv.writer(fh) w.writerow(['mercado', 'veredicto', 'corte', 'valor', 'n_validos', 'mediana_razon', 'ic95_lo', 'ic95_hi', 'p10', 'p90', 'pct_dentro_15', 'pct_por_encima_115', 'ic95_pct_lo', 'ic95_pct_hi']) for m in R: for corte in ('todos', 'por_anio', 'por_producto', 'por_tipo_organo', 'por_menor'): items = [('todos', R[m]['todos'])] if corte == 'todos' else sorted(R[m][corte].items()) for k, x in items: if not x.get('n'): continue w.writerow([m, ver[m]['veredicto'], corte, k, x['n'], round(x['mediana'], 4), round(x['ic95'][0], 4), round(x['ic95'][1], 4), round(x['p10'], 4), round(x['p90'], 4), round(x['pct_dentro_15'], 1), round(x['pct_por_encima'], 1), round(x['ic95_pct_por_encima'][0], 1), round(x['ic95_pct_por_encima'][1], 1)]) with open('/p/salidas/publicable_organo.csv', 'w', newline='') as fh: w = csv.writer(fh) w.writerow(['mercado', 'producto', 'organo', 'tipo_organo', 'n_validos', 'k_por_encima_115', 'mediana_razon', 'ic95_lo', 'ic95_hi', 'hecho']) for o in O: if ver[o['mercado']]['veredicto'] != 'PASA' or o['nif_persona'] == 'True': continue w.writerow([o['mercado'], o['producto'], o['organo_nombre'], o['tipo_organo'], o['n'], o['k_por_encima'], round(float(o['mediana']), 4), round(float(o['ic95_lo']), 4), round(float(o['ic95_hi']), 4), o['hecho']]) print(json.dumps({m: (x['veredicto'], x['fallan']) for m, x in ver.items()}, ensure_ascii=False))