#!/usr/bin/env python3 """Compare the session's own blind re-tags of a random 5% sample with the helper tags (spec 9.6). Mine: ~/research-cache/.../spot/mine_*.txt, one line per post: num|role|beginner(y/n)|question_type|hardware|hardware_status|apps|apps_status|platform|platform_status|pain|budget_huf|resolved Theirs: ~/research-cache/.../tags/tags_*.csv Agreement per column = exact match of the normalised value (sets for ;-lists; hardware compared by class, the bracketed model dropped). Prints overall agreement and agreement where either side is non-empty (the strict view: empty-vs-empty agreement inflates the overall rate). Usage: python3 spotcheck.py (v1: every column, helper tags/ vs spot/mine_*.txt) python3 spotcheck.py --v2 (v2 re-tag: role, hardware, hardware_status; tags_v2/v2_*.csv vs spot/mine_v2.txt num|role|hardware|hardware_status) """ import csv import glob import os import re import sys CACHE = os.path.expanduser("~/research-cache/prohardver-hazi-szerver") COLS = ["role", "beginner", "question_type", "hardware", "hardware_status", "apps", "apps_status", "platform", "platform_status", "pain", "budget_huf", "resolved"] SETS = {"question_type", "hardware", "apps", "platform", "pain"} def norm(col, v): v = (v or "").strip() if col in SETS: parts = [re.sub(r"\s*\(.*?\)", "", x).strip().lower() for x in v.split(";")] return tuple(sorted(x for x in parts if x)) if col == "budget_huf": return v.split(".")[0] return v.lower() def main_v2(): cols = ["role", "hardware", "hardware_status"] theirs = {} for f in glob.glob(os.path.join(CACHE, "tags_v2", "v2_*.csv")): for r in csv.DictReader(open(f, encoding="utf-8")): theirs[int(r["num"])] = r mine = {} for line in open(os.path.join(CACHE, "spot", "mine_v2.txt"), encoding="utf-8"): v = line.rstrip("\n").split("|") mine[int(v[0])] = dict(zip(cols, v[1:])) nums = sorted(n for n in mine if n in theirs) print("v2 sample=%d compared=%d" % (len(mine), len(nums))) for c in cols: agree = sum(norm(c, mine[n][c]) == norm(c, theirs[n].get(c)) for n in nums) ne = [n for n in nums if norm(c, mine[n][c]) or norm(c, theirs[n].get(c))] agree_ne = sum(norm(c, mine[n][c]) == norm(c, theirs[n].get(c)) for n in ne) print("%-16s %7.1f%% %10.1f%% (n=%d)" % (c, 100.0 * agree / len(nums), 100.0 * agree_ne / len(ne) if ne else 100.0, len(ne))) if os.environ.get("SHOW") == c: for n in nums: if norm(c, mine[n][c]) != norm(c, theirs[n].get(c)): print(" #%d mine=%s theirs=%s" % (n, norm(c, mine[n][c]), norm(c, theirs[n].get(c)))) def main(): if "--v2" in sys.argv: return main_v2() theirs = {} for f in glob.glob(os.path.join(CACHE, "tags", "tags_*.csv")): for r in csv.DictReader(open(f, encoding="utf-8")): r["beginner"] = "y" if (r.get("beginner_evidence") or "").strip() else "n" theirs[int(r["num"])] = r mine = {} for f in glob.glob(os.path.join(CACHE, "spot", "mine_[0-9].txt")): for line in open(f, encoding="utf-8"): if not line.strip(): continue v = line.rstrip("\n").split("|") mine[int(v[0])] = dict(zip(COLS, v[1:])) nums = sorted(n for n in mine if n in theirs) print("sample=%d compared=%d (missing in helper tags: %s)" % (len(mine), len(nums), sorted(set(mine) - set(theirs)))) print("%-16s %8s %18s" % ("column", "overall", "non-empty either")) for c in COLS: agree = sum(norm(c, mine[n][c]) == norm(c, theirs[n].get(c)) for n in nums) ne = [n for n in nums if norm(c, mine[n][c]) or norm(c, theirs[n].get(c))] agree_ne = sum(norm(c, mine[n][c]) == norm(c, theirs[n].get(c)) for n in ne) print("%-16s %7.1f%% %10.1f%% (n=%d)" % (c, 100.0 * agree / len(nums), 100.0 * agree_ne / len(ne) if ne else 100.0, len(ne))) if os.environ.get("SHOW"): c = os.environ["SHOW"] for n in nums: a, b = norm(c, mine[n][c]), norm(c, theirs[n].get(c)) if a != b: print(" #%d mine=%s theirs=%s" % (n, a, b)) if __name__ == "__main__": main()