DylanJHJ/APRIL / qrel-analysis /diverse_pooling.py
DylanJHJ's picture
download
raw
2.95 kB
import argparse
import os
import random
from collections import defaultdict
def parse_trec_run(filepath, topk):
"""Return {qid: [(docid, rank), ...]} keeping only top-k per query."""
results = defaultdict(list)
with open(filepath) as f:
for line in f:
parts = line.strip().split()
if len(parts) < 6:
continue
qid, _, docid, rank = parts[0], parts[1], parts[2], int(parts[3])
results[qid].append((docid, rank))
return {qid: sorted(docs, key=lambda x: x[1])[:topk] for qid, docs in results.items()}
def rrf_fuse(system_results, rrf_k=60):
"""
system_results: list of {qid: [(docid, rank), ...]}
Returns {qid: [(docid, rrf_score), ...]} sorted by score descending.
"""
all_qids = set()
for r in system_results:
all_qids.update(r.keys())
fused = {}
counts = []
for qid in all_qids:
scores = defaultdict(float)
for i, r in enumerate(system_results):
for docid, rank in r.get(qid, []):
scores[docid] += 1.0 / (rrf_k + rank)
if i == len(system_results) - 1:
counts.append(len(scores))
fused[qid] = sorted(scores.items(), key=lambda x: -x[1])
print("Average pool size", sum(counts) / len(counts))
return fused
def write_trec_run(fused, filepath, run_name="diverse-pool"):
d = os.path.dirname(filepath)
if d:
os.makedirs(d, exist_ok=True)
with open(filepath, "w") as f:
for qid in sorted(fused.keys()):
for rank, (docid, score) in enumerate(fused[qid], start=1):
f.write(f"{qid} Q0 {docid} {rank} {score:.6f} {run_name}\n")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--run_files", nargs="+", required=True, help="TREC run files to fuse")
parser.add_argument("--output", required=True, help="Output file path for the fused run")
parser.add_argument("--topk", type=int, default=10, help="Top-K docs per system per query")
parser.add_argument("--rrf_k", type=int, default=60, help="RRF smoothing constant")
parser.add_argument("--seed", type=int, default=None, help="If set, randomly shuffle the RRF ranking with this seed")
args = parser.parse_args()
print(f"Fusing {len(args.run_files)} systems (top-{args.topk} each) ...")
for fp in args.run_files:
print(f" {fp}")
system_results = [parse_trec_run(fp, args.topk) for fp in args.run_files]
fused = rrf_fuse(system_results, rrf_k=args.rrf_k)
if args.seed is not None:
rng = random.Random(args.seed)
for qid in fused:
rng.shuffle(fused[qid])
print(f"Shuffled ranking with seed={args.seed}")
write_trec_run(fused, args.output)
total_docs = sum(len(v) for v in fused.values())
print(f"-> {args.output} ({len(fused)} queries, {total_docs} total docs)")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
2.95 kB
·
Xet hash:
fa427221d7add03a2bc03570532f72905d40ac334c7cd6165c307f5f84ed1cdd

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.