web-dev-qa-db-ja.com

spaCyで依存関係ツリーを取得する方法は?

私はspaCyで依存関係ツリーを取得する方法を見つけようとしましたが、ツリーを取得する方法については何も見つけることができませんでした、 ツリーをナビゲートする方法

40
Nicolas Joseph

結局のところ、ツリーはドキュメントで利用可能です トークンを介して

ツリーのルートを検索したい場合は、ドキュメントにアクセスできます。

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

次に、ツリーをナビゲートするために、トークンには 子を介して を取得するAPIがあります

7
Nicolas Joseph

誰かがspacyによって生成された依存関係ツリーを簡単に表示したい場合、1つの解決策はそれを nltk.tree.Tree および nltk.tree.Tree.pretty_print メソッド。以下に例を示します。

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]

出力:

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

Edit:トークン表現を変更するために、これを行うことができます:

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)

結果:

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

ツリーはそれ自体がオブジェクトではありません。トークン間の関係を介してナビゲートするだけです。そのため、ドキュメントではツリーのナビゲーションについて説明していますが、「取得」については説明していません。

まず、テキストを解析して Doc オブジェクトを取得しましょう。

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

docSequenceToken オブジェクトです:

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

ただし、単一のルートトークンはありません。 3つの文で構成されるテキストを解析したため、3つの異なるツリーがあり、それぞれに独自のルートがあります。各文のルートから解析を開始する場合、最初に文を個別のオブジェクトとして取得すると役立ちます。幸いなことに、docはこれらを .sents プロパティ:

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

これらの各文は Span with .rootそのルートトークンを指すプロパティ。通常、ルートトークンは文の主要な動詞になります(ただし、動詞のない文などの異常な文構造には当てはまらない場合があります)。

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

ルートトークンが見つかったら、.children各トークンのプロパティ。たとえば、最初の文の動詞の主語と目的語を見つけましょう。 .dep_各子トークンのプロパティ 親との関係を記述 ;たとえば、dep_ of 'nsubj'は、トークンがその親の名義的なサブジェクトであることを意味します。

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

同様に、これらのトークンの子の1つを表示することにより、ツリーをたどっていきます。

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

したがって、上記のプロパティを使用して、ツリー全体をナビゲートできます。構造の理解に役立つように、例文の依存ツリーを視覚化する場合は、 displaCy で遊ぶことをお勧めします。

35
Mark Amery

これが新しいAPI呼び出しかどうかはわかりませんが、Documentクラスに.print_tree()メソッドがあり、これをすばやく実行できます。

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

依存関係ツリーをJSONにダンプします。それは複数の文の根とそのすべてを扱います:

    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))

名前print_ treeは少し誤った名前で、メソッド自体は何も出力せず、各文に1つずつ辞書のリストを返します。

7

以下のライブラリを使用して、依存関係ツリーを表示できます。非常に便利です。

from spacy import displacy

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

また、完全なコードの下でそれを行う必要がありました:

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)

そして、ターミナルの間隔が必要な場合:

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