mirror of
https://github.com/explosion/spaCy.git
synced 2024-11-15 22:27:12 +03:00
7e4cd7575c
* Refactor Docs.is_ flags * Add derived `Doc.has_annotation` method * `Doc.has_annotation(attr)` returns `True` for partial annotation * `Doc.has_annotation(attr, require_complete=True)` returns `True` for complete annotation * Add deprecation warnings to `is_tagged`, `is_parsed`, `is_sentenced` and `is_nered` * Add `Doc._get_array_attrs()`, which returns a full list of `Doc` attrs for use with `Doc.to_array`, `Doc.to_bytes` and `Doc.from_docs`. The list is the `DocBin` attributes list plus `SPACY` and `LENGTH`. Notes on `Doc.has_annotation`: * `HEAD` is converted to `DEP` because heads don't have an unset state * Accept `IS_SENT_START` as a synonym of `SENT_START` Additional changes: * Add `NORM`, `ENT_ID` and `SENT_START` to default attributes for `DocBin` * In `Doc.from_array()` the presence of `DEP` causes `HEAD` to override `SENT_START` * In `Doc.from_array()` using `attrs` other than `Doc._get_array_attrs()` (i.e., a user's custom list rather than our default internal list) with both `HEAD` and `SENT_START` shows a warning that `HEAD` will override `SENT_START` * `set_children_from_heads` does not require dependency labels to set sentence boundaries and sets `sent_start` for all non-sentence starts to `-1` * Fix call to set_children_form_heads Co-authored-by: Matthew Honnibal <honnibal+gh@gmail.com>
40 lines
1.5 KiB
Python
40 lines
1.5 KiB
Python
from typing import Union, Iterator
|
|
|
|
from ...symbols import NOUN, PROPN, PRON
|
|
from ...errors import Errors
|
|
from ...tokens import Doc, Span
|
|
|
|
|
|
def noun_chunks(doclike: Union[Doc, Span]) -> Iterator[Span]:
|
|
"""Detect base noun phrases from a dependency parse. Works on Doc and Span."""
|
|
# fmt: off
|
|
labels = ["nsubj", "nsubj:pass", "obj", "iobj", "ROOT", "appos", "nmod", "nmod:poss"]
|
|
# fmt: on
|
|
doc = doclike.doc # Ensure works on both Doc and Span.
|
|
if not doc.has_annotation("DEP"):
|
|
raise ValueError(Errors.E029)
|
|
np_deps = [doc.vocab.strings[label] for label in labels]
|
|
conj = doc.vocab.strings.add("conj")
|
|
np_label = doc.vocab.strings.add("NP")
|
|
prev_end = -1
|
|
for i, word in enumerate(doclike):
|
|
if word.pos not in (NOUN, PROPN, PRON):
|
|
continue
|
|
# Prevent nested chunks from being produced
|
|
if word.left_edge.i <= prev_end:
|
|
continue
|
|
if word.dep in np_deps:
|
|
prev_end = word.right_edge.i
|
|
yield word.left_edge.i, word.right_edge.i + 1, np_label
|
|
elif word.dep == conj:
|
|
head = word.head
|
|
while head.dep == conj and head.head.i < head.i:
|
|
head = head.head
|
|
# If the head is an NP, and we're coordinated to it, we're an NP
|
|
if head.dep in np_deps:
|
|
prev_end = word.right_edge.i
|
|
yield word.left_edge.i, word.right_edge.i + 1, np_label
|
|
|
|
|
|
SYNTAX_ITERATORS = {"noun_chunks": noun_chunks}
|