67 votes

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 manière d'obtenir l'arbre, seulement sur comment naviguer dans l'arbre.

85voto

Christos Baziotis Points 2689

Si quelqu'un souhaite facilement voir l'arbre de dépendance produit par spacy, une solution serait de le convertir en un nltk.tree.Tree et d'utiliser la méthode nltk.tree.Tree.pretty_print. 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

Modifier : Pour changer la représentation du jeton, vous pouvez faire ceci :

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 donne :

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

3 votes

Mais, à mon avis, il est important d'avoir/conserver les dépendances ainsi que les postags de Spacy.

0 votes

Beau travail! Y a-t-il un moyen facile d'ajouter la balise de dépendance entre deux nœuds?

4 votes

@DavidBatista vois ma modification. Si tu veux ajouter d'autres choses à l'arbre, modifie tok_format(tok). De plus, tu devrais lire la documentation. Spacy utilise 2 représentations POS différentes tok.pos_ et tok.tag_. spacy.io/docs/#token-postags

63voto

Mark Amery Points 4705

L'arbre n'est pas un objet en soi; vous le parcourez simplement en naviguant via les relations entre les jetons. C'est pourquoi la documentation parle de naviguer dans l'arbre, mais pas de le 'récupérer'.

Tout d'abord, analysons un peu de texte pour obtenir un Doc objet :

>>> import spacy
>>> nlp = spacy.load('fr_core_news_sm')
>>> doc = nlp('D'abord, j'ai écrit quelques phrases. Ensuite, spaCy les a analysées. Hourra!')

doc est une Séquence d'objets Jeton :

>>> doc[0]
D'abord
>>> doc[1]
,
>>> doc[2]
j'
>>> doc[3]
ai

Mais il n'a pas un seul jeton racine. Nous avons analysé un texte composé de trois phrases, donc il y a trois arbres distincts, chacun avec sa propre racine. Si nous voulons commencer notre analyse à partir de la racine de chaque phrase, il sera utile d'obtenir les phrases en tant qu'objets distincts d'abord. Heureusement, doc nous expose ceux-ci via la propriété .sents :

>>> phrases = list(doc.sents)
>>> for phrase in phrases:
...     print(phrase)
... 
D'abord, j'ai écrit quelques phrases.
Ensuite, spaCy les a analysées.
Hourra!

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

>>> for phrase in phrases:
...     print(phrase.root)
... 
écrit
analysées
Hourra

Avec le jeton racine trouvé, nous pouvons naviguer dans l'arbre via la propriété .children de chaque jeton. Par exemple, trouvons le sujet et l'objet du verbe dans la première phrase. La propriété .dep_ 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.

>>> jeton_racine = phrases[0].root
>>> for enfant in jeton_racine.children:
...     if enfant.dep_ == 'nsubj':
...         sujet = enfant
...     if enfant.dep_ == 'dobj':
...         obj = enfant
... 
>>> sujet
j'
>>> obj
phrases

Nous pouvons également continuer à descendre dans l'arbre en visualisant les enfants de l'un de ces jetons :

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

Ainsi, avec les propriétés ci-dessus, vous pouvez naviguer dans l'ensemble de l'arbre. Si vous souhaitez visualiser certains arbres de dépendances pour des exemples de phrases afin de vous aider à comprendre la structure, je vous recommande d'essayer displaCy.

24voto

Rohan Points 1658

Vous pouvez utiliser la bibliothèque ci-dessous pour afficher votre arbre de dépendances, je l'ai trouvé extrêmement utile!

import spacy
from spacy import displacy

nlp = spacy.load('fr')
doc = nlp(u'Ceci est une phrase.')
displacy.serve(doc, style='dep')

Vous pouvez l'ouvrir avec votre navigateur, et cela ressemble à: displacy serve output

Pour générer un fichier SVG:

from pathlib import Path

output_path = Path("votrechemin/.svg")
svg = displacy.render(doc, style='dep')
with output_path.open("w", encoding="utf-8") as fh:
    fh.write(svg)

3 votes

JFI.. l'option server ouvre également l'arbre en tant que lien web. Pour une image statique (l'option de rendu est disponible displacy.render(doc, style='dep')

2 votes

Pour compléter le commentaire de @prashanth, vous pouvez également imprimer sur une image (que vous pouvez ouvrir/afficher, par exemple, dans Firefox; notez que vous devez spécifier le chemin complet (/home/victoria/..., pas ~/...). Code : from pathlib import Path; output_path = Path("/home/victoria/dependency_plot.svg"); svg = displacy.render(doc, style='dep', jupyter=False); output_path.open("w", encoding="utf-8").write(svg)

0 votes

Étrangement, lorsque je rends en tant que svg, les balises de dépendance sont manquantes, lorsque je rends avec serve, elles sont imprimées.

8voto

Nicolas Joseph Points 794

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

Si vous souhaitez trouver la racine de l'arbre, vous pouvez simplement parcourir 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 pour accéder à travers les enfants

4 votes

Un document aura 1 racine par phrase

1 votes

Il n'est pas nécessaire d'itérer sur les jetons pour trouver la racine ; vous pouvez simplement accéder à la propriété .root d'une phrase. Je posterai ma propre réponse montrant ceci.

6voto

Krzysiek Points 339

J'ai également besoin de le faire, donc voici le code complet ci-dessous :

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 souhaitez ajouter de l'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)

0 votes

Je viens de rajouter un module pour l'impression ainsi que pour associer un arbre (ou trouver des nœuds) sur un motif regex. Si cela vous intéresse, voici le lien : github.com/krzysiekfonal/grammaregex Ce n'est pas encore prêt à être installé mais cela devrait être fait cette semaine et être disponible via pip.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X