Download analysis/designed-difficulty/prepare_data.py from Station-house/ConspiracyBench: direct link, hf CLI and curl.
- Browser
- Download file 4.89 kB
-
https://huggingface.co/spaces/Station-house/ConspiracyBench/resolve/main/analysis/designed-difficulty/prepare_data.py
- Command line
-
hf download hf://spaces/Station-house/ConspiracyBench/analysis/designed-difficulty/prepare_data.py
-
curl -L -o prepare_data.py https://huggingface.co/spaces/Station-house/ConspiracyBench/resolve/main/analysis/designed-difficulty/prepare_data.py
4.89 kB
| import json | |
| import re | |
| from pathlib import Path | |
| import pandas as pd | |
| ROOT = Path("completed_experiments/evals/full-2026-10-23/outputs") | |
| CORPUS = Path("questions/corpus.jsonl") | |
| OUT = Path("analysis/designed-difficulty") | |
| MODELS = [ | |
| "qwen3.5-4b", | |
| "gemma-4-e4b", | |
| "granite-4.2-3b", | |
| "nemotron-3-nano-4b", | |
| "k2-horizon-3.7b", | |
| ] | |
| PATTERN = re.compile( | |
| r"^(?P<variant>[^/]+)/(?P<question_id>[^#]+)" | |
| r"#e(?P<epoch>\d+)#t(?P<turn>\d+)$" | |
| ) | |
| # 1. Load question metadata | |
| questions = {} | |
| with CORPUS.open(encoding="utf-8") as f: | |
| for line in f: | |
| if not line.strip(): | |
| continue | |
| q = json.loads(line) | |
| qid = q["id"] | |
| if qid in questions: | |
| raise ValueError(f"Duplicate question ID: {qid}") | |
| difficulty = q.get("difficulty") or {} | |
| questions[qid] = { | |
| "claim_id": q.get("claim_id"), | |
| "category": q.get("category"), | |
| "framing": q.get("framing"), | |
| "evidence_scarcity": difficulty.get("evidence_scarcity"), | |
| "question_openness": difficulty.get("question_openness"), | |
| "band": difficulty.get("band"), | |
| } | |
| print("Corpus questions:", len(questions)) | |
| # 2. Load judge results | |
| rows = [] | |
| unparsed = [] | |
| for model in MODELS: | |
| path = ROOT / model / "pplx/results.jsonl" | |
| if not path.exists(): | |
| raise FileNotFoundError(path) | |
| count = 0 | |
| with path.open(encoding="utf-8") as f: | |
| for line_no, line in enumerate(f, 1): | |
| if not line.strip(): | |
| continue | |
| result = json.loads(line) | |
| case_id = result.get("case_id", "") | |
| match = PATTERN.fullmatch(case_id) | |
| if not match: | |
| unparsed.append((model, line_no, case_id)) | |
| continue | |
| parts = match.groupdict() | |
| qid = parts["question_id"] | |
| meta = questions.get(qid, {}) | |
| probabilities = result.get("probabilities") or {} | |
| rows.append({ | |
| "model": model, | |
| "variant": parts["variant"], | |
| "question_id": qid, | |
| "epoch": int(parts["epoch"]), | |
| "turn": int(parts["turn"]), | |
| "case_id": case_id, | |
| "choice": result.get("choice"), | |
| "status": result.get("status"), | |
| "dropped": result.get("dropped"), | |
| "confidence": result.get("confidence"), | |
| "p_hold": probabilities.get("hold"), | |
| "p_diverge": probabilities.get("diverge"), | |
| "p_abstain": probabilities.get("abstain"), | |
| **meta, | |
| }) | |
| count += 1 | |
| print(f"{model}: {count:,} records") | |
| df = pd.DataFrame(rows) | |
| if df.empty: | |
| raise RuntimeError("No parsed Judge records found") | |
| # 3. Integrity checks | |
| key_cols = ["model", "case_id"] | |
| duplicates = df.duplicated(key_cols, keep=False) | |
| missing_metadata = df["evidence_scarcity"].isna() | df["question_openness"].isna() | |
| valid_labels = {"hold", "diverge", "abstain"} | |
| df["valid"] = ( | |
| df["status"].eq("ok") | |
| & df["dropped"].eq(0) | |
| & df["choice"].isin(valid_labels) | |
| ) | |
| df["diverged"] = df["choice"].eq("diverge") & df["valid"] | |
| print("\n=== INTEGRITY CHECK ===") | |
| print("Total records:", len(df)) | |
| print("Unparsed case IDs:", len(unparsed)) | |
| print("Duplicate model/case IDs:", int(duplicates.sum())) | |
| print("Missing difficulty metadata:", int(missing_metadata.sum())) | |
| print("Valid Judge records:", int(df["valid"].sum())) | |
| print("\nStatus distribution:") | |
| print(df["status"].value_counts(dropna=False).to_string()) | |
| print("\nChoice distribution:") | |
| print(df["choice"].value_counts(dropna=False).to_string()) | |
| print("\nVariant distribution:") | |
| print(pd.crosstab(df["model"], df["variant"]).to_string()) | |
| if unparsed: | |
| print("\nUnparsed examples:", unparsed[:10]) | |
| # 4. Save the raw joined dataset | |
| OUT.mkdir(parents=True, exist_ok=True) | |
| output = OUT / "baseline_joined.csv" | |
| df.to_csv(output, index=False) | |
| print(f"\nSaved: {output}") | |
| # 5. Preliminary summary (only if integrity checks pass) | |
| if duplicates.any() or missing_metadata.any() or unparsed: | |
| print("\nWARNING: Resolve integrity issues before computing rates.") | |
| else: | |
| opening = df[(df["variant"] == "multiturn") & (df["turn"] == 0)] | |
| print("\n=== MULTITURN OPENING: DIVERGENCE RATE ===") | |
| print("Denominator: valid hold/diverge/abstain judgments") | |
| summary = ( | |
| opening[opening["valid"]] | |
| .groupby("model") | |
| .agg( | |
| n=("diverged", "size"), | |
| questions=("question_id", "nunique"), | |
| diverged=("diverged", "sum"), | |
| rate=("diverged", "mean"), | |
| ) | |
| .reset_index() | |
| ) | |
| summary["rate_pct"] = (summary["rate"] * 100).round(2) | |
| print( | |
| summary[ | |
| ["model", "questions", "n", "diverged", "rate_pct"] | |
| ].to_string(index=False) | |
| ) | |