web-dev-qa-db-fra.com

Comment obtenir l'arbre de dépendance avec spaCy?

J'ai essayé de trouver comment obtenir l'arbre de dépendance avec spaCy mais je ne trouve rien sur la façon d'obtenir l'arbre, mais uniquement sur comment naviguer dans l'arbre .

40
Nicolas Joseph

Il s’avère que l’arbre est disponible à travers les jetons dans un document.

Voudriez-vous trouver la racine de l’arbre, vous pouvez simplement consulter le document:

def find_root(docu):
    for token in docu:
        if token.head is token:
            return token

Pour ensuite naviguer dans l’arbre, les jetons ont une API à obtenir à travers les enfants

7
Nicolas Joseph

Au cas où quelqu'un voudrait voir facilement l'arbre de dépendance produit par spacy, une solution consisterait à le convertir en nltk.tree.Tree et utilisez le nltk.tree.Tree.pretty_print méthode. Voici un exemple:

import spacy
from nltk import Tree


en_nlp = spacy.load('en')

doc = en_nlp("The quick brown fox jumps over the lazy dog.")

def to_nltk_tree(node):
    if node.n_lefts + node.n_rights > 0:
        return Tree(node.orth_, [to_nltk_tree(child) for child in node.children])
    else:
        return node.orth_


[to_nltk_tree(sent.root).pretty_print() for sent in doc.sents]

Sortie:

                jumps                  
  ________________|____________         
 |    |     |     |    |      over     
 |    |     |     |    |       |        
 |    |     |     |    |      dog      
 |    |     |     |    |    ___|____    
The quick brown  fox   .  the      lazy

Edit: Pour modifier la représentation du jeton, vous pouvez procéder comme suit:

def tok_format(tok):
    return "_".join([tok.orth_, tok.tag_])


def to_nltk_tree(node):
    if node.n_lefts + node.n_rights > 0:
        return Tree(tok_format(node), [to_nltk_tree(child) for child in node.children])
    else:
        return tok_format(node)

Ce qui résulte en:

                         jumps_VBZ                           
   __________________________|___________________             
  |       |        |         |      |         over_IN        
  |       |        |         |      |            |            
  |       |        |         |      |          dog_NN        
  |       |        |         |      |     _______|_______     
The_DT quick_JJ brown_JJ   fox_NN  ._. the_DT         lazy_JJ
53
Christos Baziotis

L'arbre n'est pas un objet en soi; vous venez de naviguer via les relations entre les jetons. C'est pourquoi les docs parlent de naviguer dans l'arborescence, mais pas de "l'obtenir".

Commençons par analyser du texte pour obtenir un objet Doc :

>>> import spacy
>>> nlp = spacy.load('en')
>>> doc = nlp('First, I wrote some sentences. Then spaCy parsed them. Hooray!')

doc est un Sequence de Token objets:

>>> doc[0]
First
>>> doc[1]
,
>>> doc[2]
I
>>> doc[3]
wrote

Mais il n'a pas de jeton racine unique. Nous avons analysé un texte composé de trois phrases. Il existe donc trois arbres distincts, chacun avec sa propre racine. Si nous voulons commencer notre analyse à partir de la racine de chaque phrase, cela aidera d’abord à obtenir les phrases comme objets distincts. Heureusement, doc nous les expose via le .sents propriété:

>>> sentences = list(doc.sents)
>>> for sentence in sentences:
...     print(sentence)
... 
First, I wrote some sentences.
Then spaCy parsed them.
Hooray!

Chacune de ces phrases est un Span avec un .root propriété pointant vers son jeton racine. Généralement, le jeton racine sera le verbe principal de la phrase (bien que cela puisse ne pas être vrai pour les structures de phrases inhabituelles, telles que les phrases sans verbe):

>>> for sentence in sentences:
...     print(sentence.root)
... 
wrote
parsed
Hooray

Avec le jeton racine trouvé, nous pouvons naviguer dans l’arbre via le .children propriété de chaque jeton. Par exemple, trouvons le sujet et l'objet du verbe dans la première phrase. Le .dep_ propriété de chaque jeton enfant décrit sa relation avec son parent ; par exemple un dep_ de 'nsubj' _ signifie qu'un jeton est le sujet nominal de son parent.

>>> root_token = sentences[0].root
>>> for child in root_token.children:
...     if child.dep_ == 'nsubj':
...         subj = child
...     if child.dep_ == 'dobj':
...         obj = child
... 
>>> subj
I
>>> obj
sentences

Nous pouvons également continuer à descendre l'arbre en regardant l'un des enfants de ces jetons:

>>> list(obj.children)
[some]

Ainsi, avec les propriétés ci-dessus, vous pouvez parcourir l’arbre entier. Si vous souhaitez visualiser des arbres de dépendance, par exemple des phrases pour vous aider à comprendre la structure, je vous recommande de jouer avec affichage .

35
Mark Amery

Je ne sais pas s'il s'agit d'un nouvel appel d'API ou quoi, mais il existe une méthode .print_tree () sur la classe Document qui permet de résoudre rapidement ce problème.

https://spacy.io/api/doc#print_tree

Il vide l’arbre de dépendance en JSON. Il traite des racines de phrases multiples et de tout ça:

    import spacy    
    nlp = spacy.load('en')
    doc1 = nlp(u'This is the way the world ends.  So you say.')  
    print(doc1.print_tree(light=True))

Le nom print _ tree est un peu impropre, la méthode elle-même n’imprime rien, elle renvoie plutôt une liste de dict, une pour chaque phrase. .

7
Christopher Reiss

Vous pouvez utiliser la bibliothèque ci-dessous pour afficher votre arbre de dépendances, cela s’est révélé extrêmement utile!

from spacy import displacy

nlp = spacy.load('en')
doc = nlp(u'This is a sentence.')
displacy.serve(doc, style='dep')
6
Rohan

Je devais aussi le faire en dessous du code complet:

import sys
def showTree(sent):
    def __showTree(token):
        sys.stdout.write("{")
        [__showTree(t) for t in token.lefts]
        sys.stdout.write("%s->%s(%s)" % (token,token.dep_,token.tag_))
        [__showTree(t) for t in token.rights]
        sys.stdout.write("}")
    return __showTree(sent.root)

Et si vous voulez un espacement pour le terminal:

def showTree(sent):
    def __showTree(token, level):
        tab = "\t" * level
        sys.stdout.write("\n%s{" % (tab))
        [__showTree(t, level+1) for t in token.lefts]
        sys.stdout.write("\n%s\t%s [%s] (%s)" % (tab,token,token.dep_,token.tag_))
        [__showTree(t, level+1) for t in token.rights]
        sys.stdout.write("\n%s}" % (tab))
    return __showTree(sent.root, 1)
5
Krzysiek