PoPTard5 / model-3 /scripts /ens_probe.py
Jyo-K's picture
Upload folder using huggingface_hub
e79d917 verified
Raw History Blame Contribute Delete
3.88 kB
"""Sizing an ensemble with Chinmay's bge-m3 run (leaderboard 0.966) against ours (0.976423).
F0.5 break-even, derived exactly: for one entity F0.5 = 1.25*TP/(0.25*T + k). Adding a
candidate changes the denominator D = 0.25T + k by +1. Adding a TP gains
1.25(D-TP)/(D(D+1)); adding an FP loses 1.25*TP/(D(D+1)). So an extra pair is worth taking
iff its TP:FP ratio beats TP/(D-TP), which at P=R=1 (T=k, D=1.25T) is exactly 4:1 - i.e.
the added pairs need precision > 80%.
This measures the SIZE of each disagreement region on the real test set, per country, so
the break-even requirement can be applied. It cannot measure their precision (no test
labels) - that is what a submission buys.
"""
import sys
import numpy as np, pandas as pd
sys.path.insert(0, "src")
import config as C
OURS = "output/matching_results.tsv"
HIS = "/scratch/user4/dai/bge-out/runs/full_20260926T001535Z_f7bdb9/output/matching_results.tsv"
def load(p):
d = pd.read_csv(p, sep="\t", dtype=str, keep_default_na=False)
print(f" {p.split('/')[-1]:<22} cols={list(d.columns)} rows={len(d):,}")
a, b = d.columns[0], d.columns[1]
out = {}
for q, v in zip(d[a], d[b]):
s = {x for x in str(v).split(",") if x}
if s:
out[q] = s
return out
print("loading both submissions")
A, B = load(OURS), load(HIS)
s1 = pd.read_parquet(C.PATHS["test"]["source1"], columns=["entity_id", "country_norm"])
ctry = dict(zip(s1["entity_id"], s1["country_norm"].astype(str)))
allq = list(s1["entity_id"])
print(f"\ntest entities {len(allq):,} ours non-empty {len(A):,} his non-empty {len(B):,}")
rows = []
for q in allq:
a, b = A.get(q, set()), B.get(q, set())
rows.append((ctry.get(q, "?"), len(a), len(b), len(a & b), len(a - b), len(b - a)))
df = pd.DataFrame(rows, columns=["ctry", "na", "nb", "both", "only_a", "only_b"])
print("\n" + "=" * 78)
print("AGREEMENT STRUCTURE (pairs, per country)")
print("=" * 78)
g = df.groupby("ctry")[["na", "nb", "both", "only_a", "only_b"]].sum()
g["entities"] = df.groupby("ctry").size()
g["jaccard"] = g["both"] / (g["both"] + g["only_a"] + g["only_b"])
g["onlyB_per_entity"] = g["only_b"] / g["entities"]
print(g.to_string())
tot = g.sum(numeric_only=True)
print(f"\n TOTAL ours {int(tot['na']):,} his {int(tot['nb']):,} agree {int(tot['both']):,}")
print(f" ours-only {int(tot['only_a']):,} HIS-ONLY {int(tot['only_b']):,}")
print(f" overall jaccard {tot['both']/(tot['both']+tot['only_a']+tot['only_b']):.4f}")
print("\n" + "=" * 78)
print("WHAT A UNION WOULD ADD, and the precision it must clear")
print("=" * 78)
for c in g.index:
add = g.at[c, "only_b"]
cur = g.at[c, "na"]
n = g.at[c, "entities"]
print(f" {c:<8} adds {add:>9,} pairs to {cur:>9,} ({add/max(cur,1):>6.2%} more), "
f"{add/n:>5.3f}/entity -> must exceed 80% precision to help")
print("\n" + "=" * 78)
print("HOW MANY OF HIS EXCLUSIVE PAIRS WERE EVEN IN OUR CANDIDATE SET?")
print("=" * 78)
print(" (pairs we never retrieved are the ones an ensemble uniquely unlocks; pairs we")
print(" retrieved and rejected we already priced at p < 0.70 and measured as a losing")
print(" trade at 1.9 TP per FP)")
cp = pd.read_csv("output/candidate_pairs.tsv", sep="\t", dtype=str,
keep_default_na=False, nrows=None)
print(f" our candidate_pairs.tsv: cols={list(cp.columns)} rows={len(cp):,}")
ca, cb = cp.columns[0], cp.columns[1]
cand = {}
for q, v in zip(cp[ca], cp[cb]):
s = {x for x in str(v).split(",") if x}
if s:
cand[q] = s
inc = nev = 0
for q in allq:
ex = B.get(q, set()) - A.get(q, set())
if not ex:
continue
cs = cand.get(q, set())
inc += len(ex & cs)
nev += len(ex - cs)
print(f" his-exclusive pairs INSIDE our candidates : {inc:,} (we scored and rejected)")
print(f" his-exclusive pairs we NEVER retrieved : {nev:,} (genuinely new)")