2017-04-15 13:05:47 +03:00
|
|
|
# coding: utf8
|
|
|
|
from __future__ import division, print_function, unicode_literals
|
2015-03-11 04:07:03 +03:00
|
|
|
|
2018-03-27 20:23:02 +03:00
|
|
|
from .gold import tags_to_entities, GoldParse
|
2015-05-27 04:18:16 +03:00
|
|
|
|
2015-04-05 23:29:30 +03:00
|
|
|
|
2015-05-24 21:07:18 +03:00
|
|
|
class PRFScore(object):
|
2017-04-15 12:59:21 +03:00
|
|
|
"""
|
|
|
|
A precision / recall / F score
|
|
|
|
"""
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
|
2015-05-24 21:07:18 +03:00
|
|
|
def __init__(self):
|
|
|
|
self.tp = 0
|
|
|
|
self.fp = 0
|
|
|
|
self.fn = 0
|
|
|
|
|
|
|
|
def score_set(self, cand, gold):
|
|
|
|
self.tp += len(cand.intersection(gold))
|
|
|
|
self.fp += len(cand - gold)
|
|
|
|
self.fn += len(gold - cand)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def precision(self):
|
|
|
|
return self.tp / (self.tp + self.fp + 1e-100)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def recall(self):
|
|
|
|
return self.tp / (self.tp + self.fn + 1e-100)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def fscore(self):
|
|
|
|
p = self.precision
|
|
|
|
r = self.recall
|
|
|
|
return 2 * ((p * r) / (p + r + 1e-100))
|
|
|
|
|
|
|
|
|
2015-03-11 04:07:03 +03:00
|
|
|
class Scorer(object):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""Compute evaluation scores."""
|
|
|
|
|
2015-03-11 04:07:03 +03:00
|
|
|
def __init__(self, eval_punct=False):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""Initialize the Scorer.
|
|
|
|
|
|
|
|
eval_punct (bool): Evaluate the dependency attachments to and from
|
|
|
|
punctuation.
|
|
|
|
RETURNS (Scorer): The newly created object.
|
|
|
|
|
|
|
|
DOCS: https://spacy.io/api/scorer#init
|
|
|
|
"""
|
2015-05-24 21:07:18 +03:00
|
|
|
self.tokens = PRFScore()
|
|
|
|
self.sbd = PRFScore()
|
|
|
|
self.unlabelled = PRFScore()
|
|
|
|
self.labelled = PRFScore()
|
|
|
|
self.tags = PRFScore()
|
|
|
|
self.ner = PRFScore()
|
2019-07-09 21:54:59 +03:00
|
|
|
self.ner_per_ents = dict()
|
2015-03-11 04:07:03 +03:00
|
|
|
self.eval_punct = eval_punct
|
|
|
|
|
|
|
|
@property
|
|
|
|
def tags_acc(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Part-of-speech tag accuracy (fine grained tags,
|
|
|
|
i.e. `Token.tag`).
|
|
|
|
"""
|
2015-05-24 21:07:18 +03:00
|
|
|
return self.tags.fscore * 100
|
2015-05-24 03:49:56 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def token_acc(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Tokenization accuracy."""
|
2015-06-28 07:21:38 +03:00
|
|
|
return self.tokens.precision * 100
|
2015-03-11 04:07:03 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def uas(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Unlabelled dependency score."""
|
2015-05-24 21:07:18 +03:00
|
|
|
return self.unlabelled.fscore * 100
|
2015-03-11 04:07:03 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def las(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Labelled depdendency score."""
|
2015-05-24 21:07:18 +03:00
|
|
|
return self.labelled.fscore * 100
|
2015-03-11 04:07:03 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def ents_p(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Named entity accuracy (precision)."""
|
2015-05-27 04:18:16 +03:00
|
|
|
return self.ner.precision * 100
|
2015-03-11 04:07:03 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def ents_r(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Named entity accuracy (recall)."""
|
2015-05-27 04:18:16 +03:00
|
|
|
return self.ner.recall * 100
|
2015-04-19 11:31:31 +03:00
|
|
|
|
2015-03-11 04:07:03 +03:00
|
|
|
@property
|
|
|
|
def ents_f(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (float): Named entity accuracy (F-score)."""
|
2015-05-27 04:18:16 +03:00
|
|
|
return self.ner.fscore * 100
|
2015-03-11 04:07:03 +03:00
|
|
|
|
2019-07-10 12:19:28 +03:00
|
|
|
@property
|
|
|
|
def ents_per_type(self):
|
|
|
|
"""RETURNS (dict): Scores per entity label.
|
|
|
|
"""
|
|
|
|
return {
|
|
|
|
k: {"p": v.precision * 100, "r": v.recall * 100, "f": v.fscore * 100}
|
|
|
|
for k, v in self.ner_per_ents.items()
|
|
|
|
}
|
|
|
|
|
2016-10-09 13:24:24 +03:00
|
|
|
@property
|
|
|
|
def scores(self):
|
2019-05-24 15:06:04 +03:00
|
|
|
"""RETURNS (dict): All scores with keys `uas`, `las`, `ents_p`,
|
|
|
|
`ents_r`, `ents_f`, `tags_acc` and `token_acc`.
|
|
|
|
"""
|
2016-10-09 13:24:24 +03:00
|
|
|
return {
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
"uas": self.uas,
|
|
|
|
"las": self.las,
|
|
|
|
"ents_p": self.ents_p,
|
|
|
|
"ents_r": self.ents_r,
|
|
|
|
"ents_f": self.ents_f,
|
2019-07-10 12:19:28 +03:00
|
|
|
"ents_per_type": self.ents_per_type,
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
"tags_acc": self.tags_acc,
|
|
|
|
"token_acc": self.token_acc,
|
2016-10-09 13:24:24 +03:00
|
|
|
}
|
|
|
|
|
2019-05-24 15:06:04 +03:00
|
|
|
def score(self, doc, gold, verbose=False, punct_labels=("p", "punct")):
|
|
|
|
"""Update the evaluation scores from a single Doc / GoldParse pair.
|
|
|
|
|
|
|
|
doc (Doc): The predicted annotations.
|
|
|
|
gold (GoldParse): The correct annotations.
|
|
|
|
verbose (bool): Print debugging information.
|
|
|
|
punct_labels (tuple): Dependency labels for punctuation. Used to
|
|
|
|
evaluate dependency attachments to punctuation if `eval_punct` is
|
|
|
|
`True`.
|
|
|
|
|
|
|
|
DOCS: https://spacy.io/api/scorer#score
|
|
|
|
"""
|
|
|
|
if len(doc) != len(gold):
|
|
|
|
gold = GoldParse.from_annot_tuples(doc, zip(*gold.orig_annot))
|
2015-05-24 21:07:18 +03:00
|
|
|
gold_deps = set()
|
|
|
|
gold_tags = set()
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
gold_ents = set(tags_to_entities([annot[-1] for annot in gold.orig_annot]))
|
2015-05-24 21:07:18 +03:00
|
|
|
for id_, word, tag, head, dep, ner in gold.orig_annot:
|
2015-05-30 19:24:32 +03:00
|
|
|
gold_tags.add((id_, tag))
|
2017-03-16 17:38:28 +03:00
|
|
|
if dep not in (None, "") and dep.lower() not in punct_labels:
|
2015-05-27 04:18:16 +03:00
|
|
|
gold_deps.add((id_, head, dep.lower()))
|
2015-05-24 21:07:18 +03:00
|
|
|
cand_deps = set()
|
|
|
|
cand_tags = set()
|
2019-05-24 15:06:04 +03:00
|
|
|
for token in doc:
|
2015-06-07 20:10:32 +03:00
|
|
|
if token.orth_.isspace():
|
|
|
|
continue
|
2015-05-30 19:24:32 +03:00
|
|
|
gold_i = gold.cand_to_gold[token.i]
|
|
|
|
if gold_i is None:
|
2018-03-27 20:23:02 +03:00
|
|
|
self.tokens.fp += 1
|
2015-05-30 19:24:32 +03:00
|
|
|
else:
|
2015-06-28 07:21:38 +03:00
|
|
|
self.tokens.tp += 1
|
2015-05-30 19:24:32 +03:00
|
|
|
cand_tags.add((gold_i, token.tag_))
|
2016-02-03 00:59:06 +03:00
|
|
|
if token.dep_.lower() not in punct_labels and token.orth_.strip():
|
2015-05-24 21:07:18 +03:00
|
|
|
gold_head = gold.cand_to_gold[token.head.i]
|
|
|
|
# None is indistinct, so we can't just add it to the set
|
|
|
|
# Multiple (None, None) deps are possible
|
|
|
|
if gold_i is None or gold_head is None:
|
|
|
|
self.unlabelled.fp += 1
|
|
|
|
self.labelled.fp += 1
|
|
|
|
else:
|
2015-05-27 04:18:16 +03:00
|
|
|
cand_deps.add((gold_i, gold_head, token.dep_.lower()))
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
if "-" not in [token[-1] for token in gold.orig_annot]:
|
2019-08-01 18:15:36 +03:00
|
|
|
# Find all NER labels in gold and doc
|
2019-08-18 16:09:16 +03:00
|
|
|
ent_labels = set([x[0] for x in gold_ents] + [k.label_ for k in doc.ents])
|
2019-08-01 18:15:36 +03:00
|
|
|
# Set up all labels for per type scoring and prepare gold per type
|
|
|
|
gold_per_ents = {ent_label: set() for ent_label in ent_labels}
|
|
|
|
for ent_label in ent_labels:
|
|
|
|
if ent_label not in self.ner_per_ents:
|
|
|
|
self.ner_per_ents[ent_label] = PRFScore()
|
2019-08-18 16:09:16 +03:00
|
|
|
gold_per_ents[ent_label].update(
|
|
|
|
[x for x in gold_ents if x[0] == ent_label]
|
|
|
|
)
|
2019-08-01 18:15:36 +03:00
|
|
|
# Find all candidate labels, for all and per type
|
2015-05-28 23:39:08 +03:00
|
|
|
cand_ents = set()
|
2019-08-01 18:15:36 +03:00
|
|
|
cand_per_ents = {ent_label: set() for ent_label in ent_labels}
|
2019-05-24 15:06:04 +03:00
|
|
|
for ent in doc.ents:
|
2015-05-28 23:39:08 +03:00
|
|
|
first = gold.cand_to_gold[ent.start]
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
last = gold.cand_to_gold[ent.end - 1]
|
2015-05-28 23:39:08 +03:00
|
|
|
if first is None or last is None:
|
|
|
|
self.ner.fp += 1
|
2019-07-09 21:54:59 +03:00
|
|
|
self.ner_per_ents[ent.label_].fp += 1
|
2015-05-28 23:39:08 +03:00
|
|
|
else:
|
|
|
|
cand_ents.add((ent.label_, first, last))
|
2019-08-01 18:15:36 +03:00
|
|
|
cand_per_ents[ent.label_].add((ent.label_, first, last))
|
2019-07-09 21:54:59 +03:00
|
|
|
# Scores per ent
|
2019-08-01 18:15:36 +03:00
|
|
|
for k, v in self.ner_per_ents.items():
|
|
|
|
if k in cand_per_ents:
|
|
|
|
v.score_set(cand_per_ents[k], gold_per_ents[k])
|
2019-07-09 21:54:59 +03:00
|
|
|
# Score for all ents
|
2015-05-28 23:39:08 +03:00
|
|
|
self.ner.score_set(cand_ents, gold_ents)
|
2015-05-27 04:18:16 +03:00
|
|
|
self.tags.score_set(cand_tags, gold_tags)
|
2015-05-24 21:07:18 +03:00
|
|
|
self.labelled.score_set(cand_deps, gold_deps)
|
|
|
|
self.unlabelled.score_set(
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
set(item[:2] for item in cand_deps), set(item[:2] for item in gold_deps)
|
2015-05-24 21:07:18 +03:00
|
|
|
)
|
2015-06-14 18:45:50 +03:00
|
|
|
if verbose:
|
|
|
|
gold_words = [item[1] for item in gold.orig_annot]
|
💫 Tidy up and auto-format .py files (#2983)
<!--- Provide a general summary of your changes in the title. -->
## Description
- [x] Use [`black`](https://github.com/ambv/black) to auto-format all `.py` files.
- [x] Update flake8 config to exclude very large files (lemmatization tables etc.)
- [x] Update code to be compatible with flake8 rules
- [x] Fix various small bugs, inconsistencies and messy stuff in the language data
- [x] Update docs to explain new code style (`black`, `flake8`, when to use `# fmt: off` and `# fmt: on` and what `# noqa` means)
Once #2932 is merged, which auto-formats and tidies up the CLI, we'll be able to run `flake8 spacy` actually get meaningful results.
At the moment, the code style and linting isn't applied automatically, but I'm hoping that the new [GitHub Actions](https://github.com/features/actions) will let us auto-format pull requests and post comments with relevant linting information.
### Types of change
enhancement, code style
## Checklist
<!--- Before you submit the PR, go over this checklist and make sure you can
tick off all the boxes. [] -> [x] -->
- [x] I have submitted the spaCy Contributor Agreement.
- [x] I ran the tests, and all new and existing tests passed.
- [x] My changes don't require a change to the documentation, or if they do, I've added all required information.
2018-11-30 19:03:03 +03:00
|
|
|
for w_id, h_id, dep in cand_deps - gold_deps:
|
|
|
|
print("F", gold_words[w_id], dep, gold_words[h_id])
|
|
|
|
for w_id, h_id, dep in gold_deps - cand_deps:
|
|
|
|
print("M", gold_words[w_id], dep, gold_words[h_id])
|