|
|
|
|
|
import sys |
|
|
|
from score.core import anchor, intersect; |
|
|
|
class Measure(object): |
|
|
|
def __init__(self, get_items): |
|
self.get_items = get_items |
|
self.g = 0 |
|
self.s = 0 |
|
self.c = 0 |
|
self.n_updates = 0 |
|
self.n_matches = 0 |
|
|
|
def update(self, gold, system, gidentities, sidentities, trace = 0): |
|
g_items = set(self.get_items(gold, gidentities)) |
|
s_items = set(self.get_items(system, sidentities)) |
|
self.g += len(g_items) |
|
self.s += len(s_items) |
|
self.c += len(g_items & s_items) |
|
self.n_updates += 1 |
|
self.n_matches += g_items == s_items |
|
if trace: |
|
return {"g": len(g_items), "s": len(s_items), |
|
"c": len(g_items & s_items), "m": 1 if g_items == s_items else 0}; |
|
|
|
def p(self): |
|
return self.c / self.s if self.s != 0 else 0.0 |
|
|
|
def r(self): |
|
return self.c / self.g if self.g != 0 else 0.0 |
|
|
|
def f(self): |
|
p = self.p() |
|
r = self.r() |
|
return 2 * p * r / (p + r) if p + r != 0 else 0.0 |
|
|
|
def m(self): |
|
return self.n_matches / self.n_updates if self.n_updates != 0 else 0.0 |
|
|
|
def report(self): |
|
json = {} |
|
json["g"] = self.g |
|
json["s"] = self.s |
|
json["c"] = self.c |
|
json["p"] = self.p() |
|
json["r"] = self.r() |
|
json["f"] = self.f() |
|
json["m"] = self.m() |
|
return json |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Scorer(object): |
|
|
|
def __init__(self, include_virtual=True): |
|
self.measures = [] |
|
self.measures.append(("labeled", Measure(self.get_itemsL))) |
|
self.measures.append(("unlabeled", Measure(self.get_itemsU))) |
|
|
|
|
|
|
|
self.include_virtual = include_virtual |
|
|
|
def identify(self, id): |
|
return self.identities[id] |
|
|
|
def get_itemsL(self, graph, identities): |
|
result = {(identities[e.src], identities[e.tgt], e.lab) for e in graph.edges} |
|
if self.include_virtual: |
|
for node in graph.nodes: |
|
if node.is_top: |
|
result.add((-1, identities[node.id], None)) |
|
return result |
|
|
|
def get_itemsU(self, graph, identities): |
|
result = {(identities[e.src], identities[e.tgt]) for e in graph.edges} |
|
if self.include_virtual: |
|
for node in graph.nodes: |
|
if node.is_top: |
|
result.add((-1, identities[node.id])) |
|
return result |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update(self, g, s, trace): |
|
gidentities = {node.id: tuple(anchor(node)) for node in g.nodes} |
|
sidentities = {node.id: tuple(anchor(node)) for node in s.nodes} |
|
scores = dict(); |
|
for key, measure in self.measures: |
|
score = measure.update(g, s, gidentities, sidentities, trace) |
|
if trace: scores[key] = score; |
|
return scores; |
|
|
|
def report(self, n, scores = None): |
|
json = {"n": n} |
|
for info, measure in self.measures: |
|
json[info] = measure.report() |
|
if scores is not None: json["scores"] = scores |
|
return json |
|
|
|
def evaluate(gold, system, format = "json", trace = 0): |
|
scorer = Scorer(include_virtual=True) |
|
n = 0 |
|
scores = dict() if trace else None |
|
for g, s in intersect(gold, system): |
|
score = scorer.update(g, s, trace) |
|
n += 1 |
|
if trace: scores[g.id] = score |
|
result = scorer.report(n, scores) |
|
return result |
|
|