# -*- coding: utf-8 -*- """Recompute the repeat-run figures from houston-repeat-run-names.csv. Each row lists, in order of first mention, the firms one run named for one question. Three runs per question and engine: the October answer and two later repeats of the same question. Overlap is the Jaccard share: firms named by both runs divided by firms named by either. python repeat_run_score.py houston-repeat-run-names.csv """ import csv import random import statistics as st import sys from collections import defaultdict PAIRS = {"october~repeat_1": ("october", "repeat_1"), "repeat_1~repeat_2": ("repeat_1", "repeat_2"), "october~repeat_2": ("october", "repeat_2")} def boot_ci(xs, n=4000, seed=20261104): rng = random.Random(seed) if not xs: return (None, None) ms = sorted(st.mean(rng.choice(xs) for _ in xs) for _ in range(n)) return (round(ms[int(.025 * n)], 3), round(ms[int(.975 * n)], 3)) def main(path): runs = defaultdict(dict) for r in csv.DictReader(open(path, encoding="utf-8", newline="")): names = [x.strip() for x in r["firms_named_in_order"].split(" | ") if x.strip()] runs[(r["engine"], r["query_id"])][r["run"]] = names for eng in sorted({k[0] for k in runs}): qs = [v for k, v in runs.items() if k[0] == eng] print(f"\n{eng}: {len(qs)} questions") for pn, (a, b) in PAIRS.items(): js, zero, same_first = [], 0, 0 for q in qs: A, B = set(q[a]), set(q[b]) if not (A | B): continue j = len(A & B) / len(A | B) js.append(j) zero += j == 0 same_first += bool(q[a]) and bool(q[b]) and q[a][0] == q[b][0] print(f" {pn}: n={len(js)} mean overlap {st.mean(js):.3f} (95% {boot_ci(js)}), median {st.median(js):.3f}, " f"no firm in common {zero / len(js):.3f}, same firm named first {same_first / len(js):.3f}") if __name__ == "__main__": main(sys.argv[1])