(doclike: types.DocLike)
Extract an ordered sequence of subject-verb-object triples from a document
    or sentence.

    Args:
        doclike

    Yields:
        Next SVO triple as (subject, verb, object), in approximate order of appearance.
Extract an ordered sequence of subject-verb-object triples from a document
    or sentence.
Extract an ordered sequence of subject - verb - object triples from a document or sentence .
def subject_verb_object_triples(doclike: types.DocLike) -> Iterable[SVOTriple]:
    """
    Extract an ordered sequence of subject-verb-object triples from a document
    or sentence.

    Args:
        doclike

    Yields:
        Next SVO triple as (subject, verb, object), in approximate order of appearance.
    """
    if isinstance(doclike, Span):
        sents = [doclike]
    else:
        sents = doclike.sents

    for sent in sents:
        # connect subjects/objects to direct verb heads
        # and expand them to include conjuncts, compound nouns, ...
        verb_sos = collections.defaultdict(lambda: collections.defaultdict(set))
        for tok in sent:
            head = tok.head
            # ensure entry for all verbs, even if empty
            # to catch conjugate verbs without direct subject/object deps
            if tok.pos == VERB:
                _ = verb_sos[tok]
            # nominal subject of active or passive verb
            if tok.dep in _NOMINAL_SUBJ_DEPS:
                if head.pos == VERB:
                    verb_sos[head]["subjects"].update(expand_noun(tok))
            # clausal subject of active or passive verb
            elif tok.dep in _CLAUSAL_SUBJ_DEPS:
                if head.pos == VERB:
                    verb_sos[head]["subjects"].update(tok.subtree)
            # nominal direct object of transitive verb
            elif tok.dep == dobj:
                if head.pos == VERB:
                    verb_sos[head]["objects"].update(expand_noun(tok))
            # prepositional object acting as agent of passive verb
            elif tok.dep == pobj:
                if head.dep == agent and head.head.pos == VERB:
                    verb_sos[head.head]["objects"].update(expand_noun(tok))
            # open clausal complement, but not as a secondary predicate
            elif tok.dep == xcomp:
                if (
                    head.pos == VERB
                    and not any(child.dep == dobj for child in head.children)
                ):
                    # TODO: just the verb, or the whole tree?
                    # verb_sos[verb]["objects"].update(expand_verb(tok))
                    verb_sos[head]["objects"].update(tok.subtree)
        # fill in any indirect relationships connected via verb conjuncts
        for verb, so_dict in verb_sos.items():
            conjuncts = verb.conjuncts
            if so_dict.get("subjects"):
                for conj in conjuncts:
                    conj_so_dict = verb_sos.get(conj)
                    if conj_so_dict and not conj_so_dict.get("subjects"):
                        conj_so_dict["subjects"].update(so_dict["subjects"])
            if not so_dict.get("objects"):
                so_dict["objects"].update(
                    obj
                    for conj in conjuncts
                    for obj in verb_sos.get(conj, {}).get("objects", [])
                )
        # expand verbs and restructure into svo triples
        for verb, so_dict in verb_sos.items():
            if so_dict["subjects"] and so_dict["objects"]:
                yield SVOTriple(
                    subject=sorted(so_dict["subjects"], key=attrgetter("i")),
                    verb=sorted(expand_verb(verb), key=attrgetter("i")),
                    object=sorted(so_dict["objects"], key=attrgetter("i")),
                )
def subject_verb_object_triples ( doclike : types . DocLike ) -> Iterable [ SVOTriple ] : if isinstance ( doclike , Span ) : sents = [ doclike ] else : sents = doclike . sents for sent in sents : # connect subjects/objects to direct verb heads # and expand them to include conjuncts, compound nouns, ... verb_sos = collections . defaultdict ( lambda : collections . defaultdict ( set ) ) for tok in sent : head = tok . head # ensure entry for all verbs, even if empty # to catch conjugate verbs without direct subject/object deps if tok . pos == VERB : _ = verb_sos [ tok ] # nominal subject of active or passive verb if tok . dep in _NOMINAL_SUBJ_DEPS : if head . pos == VERB : verb_sos [ head ] [ "subjects" ] . update ( expand_noun ( tok ) ) # clausal subject of active or passive verb elif tok . dep in _CLAUSAL_SUBJ_DEPS : if head . pos == VERB : verb_sos [ head ] [ "subjects" ] . update ( tok . subtree ) # nominal direct object of transitive verb elif tok . dep == dobj : if head . pos == VERB : verb_sos [ head ] [ "objects" ] . update ( expand_noun ( tok ) ) # prepositional object acting as agent of passive verb elif tok . dep == pobj : if head . dep == agent and head . head . pos == VERB : verb_sos [ head . head ] [ "objects" ] . update ( expand_noun ( tok ) ) # open clausal complement, but not as a secondary predicate elif tok . dep == xcomp : if ( head . pos == VERB and not any ( child . dep == dobj for child in head . children ) ) : # TODO: just the verb, or the whole tree? # verb_sos[verb]["objects"].update(expand_verb(tok)) verb_sos [ head ] [ "objects" ] . update ( tok . subtree ) # fill in any indirect relationships connected via verb conjuncts for verb , so_dict in verb_sos . items ( ) : conjuncts = verb . conjuncts if so_dict . get ( "subjects" ) : for conj in conjuncts : conj_so_dict = verb_sos . get ( conj ) if conj_so_dict and not conj_so_dict . get ( "subjects" ) : conj_so_dict [ "subjects" ] . update ( so_dict [ "subjects" ] ) if not so_dict . get ( "objects" ) : so_dict [ "objects" ] . update ( obj for conj in conjuncts for obj in verb_sos . get ( conj , { } ) . get ( "objects" , [ ] ) ) # expand verbs and restructure into svo triples for verb , so_dict in verb_sos . items ( ) : if so_dict [ "subjects" ] and so_dict [ "objects" ] : yield SVOTriple ( subject = sorted ( so_dict [ "subjects" ] , key = attrgetter ( "i" ) ) , verb = sorted ( expand_verb ( verb ) , key = attrgetter ( "i" ) ) , object = sorted ( so_dict [ "objects" ] , key = attrgetter ( "i" ) ) , )