File size: 1,934 Bytes
d3fd67f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""Shared I/O and evaluation for the BEIR reranking experiments."""
import csv
import json
import os

import numpy as np
import pytrec_eval

DATA = os.environ.get("BEIR_DATA", "beir")
OUT = os.environ.get("EXP_OUT", "out")
DATASETS = ["scifact", "nfcorpus", "fiqa", "scidocs", "trec-covid"]


def load_corpus(name):
    ids, texts, titles = [], [], []
    with open(os.path.join(DATA, name, "corpus.jsonl")) as f:
        for line in f:
            d = json.loads(line)
            ids.append(d["_id"])
            titles.append(d.get("title") or "")
            texts.append(d.get("text") or "")
    return ids, titles, texts


def load_queries(name):
    q = {}
    with open(os.path.join(DATA, name, "queries.jsonl")) as f:
        for line in f:
            d = json.loads(line)
            q[d["_id"]] = d["text"]
    return q


def load_qrels(name, split="test"):
    qrels = {}
    with open(os.path.join(DATA, name, "qrels", f"{split}.tsv")) as f:
        r = csv.reader(f, delimiter="\t")
        next(r)
        for qid, did, score in r:
            qrels.setdefault(qid, {})[did] = int(score)
    return qrels


def evaluate(run, qrels, ks=(3, 5, 10)):
    """run: {qid: {docid: score}}. Returns mean nDCG@k and Recall@k (BEIR/pytrec_eval conventions)."""
    measures = {f"ndcg_cut.{','.join(map(str, ks))}", f"recall.{','.join(map(str, ks))}"}
    q = {k: v for k, v in qrels.items() if k in run}
    ev = pytrec_eval.RelevanceEvaluator(q, measures)
    res = ev.evaluate({k: run[k] for k in q})
    out = {}
    for k in ks:
        out[f"nDCG@{k}"] = float(np.mean([r[f"ndcg_cut_{k}"] for r in res.values()]))
        out[f"R@{k}"] = float(np.mean([r[f"recall_{k}"] for r in res.values()]))
    return out, res


def order_to_run(order_ids):
    """Selected ordered list -> descending pseudo-scores so pytrec_eval keeps the order."""
    n = len(order_ids)
    return {d: float(n - i) for i, d in enumerate(order_ids)}