如何使用spaCy获取依赖树?

Nic*_*eph 41 python spacy

我一直试图找到如何使用spaCy获取依赖树,但我找不到任何关于如何获取树的信息,只关于如何导航树.

Chr*_*tis 54

如果有人想要轻松查看spacy生成的依赖关系树,一种解决方案是将其转换为a 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]
Run Code Online (Sandbox Code Playgroud)

输出:

                jumps                  
  ________________|____________         
 |    |     |     |    |      over     
 |    |     |     |    |       |        
 |    |     |     |    |      dog      
 |    |     |     |    |    ___|____    
The quick brown  fox   .  the      lazy
Run Code Online (Sandbox Code Playgroud)

编辑:要更改令牌表示,您可以执行以下操作:

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)
Run Code Online (Sandbox Code Playgroud)

结果如下:

                         jumps_VBZ                           
   __________________________|___________________             
  |       |        |         |      |         over_IN        
  |       |        |         |      |            |            
  |       |        |         |      |          dog_NN        
  |       |        |         |      |     _______|_______     
The_DT quick_JJ brown_JJ   fox_NN  ._. the_DT         lazy_JJ
Run Code Online (Sandbox Code Playgroud)

  • 但在我看来,拥有/保持依赖关系以及Spacy的postags是很重要的. (2认同)
  • @DavidBatista看到我的编辑.如果你想在树上添加一些其他内容编辑`tok_format(tok)`.你也应该阅读文档.Spacy使用2种不同的POS表示形式`tok.pos_`和`tok.tag_`.https://spacy.io/docs/#token-postags (2认同)
  • `tok.dep_`属性也可以与`tok.tag_`一起使用来表示语法依赖关系. (2认同)

Mar*_*ery 35

树本身不是一个物体; 你只需通过令牌之间的关系来导航它.这就是为什么文档谈论导航树,而不是'得到'它.

首先,让我们解析一些文本来获取一个Doc对象:

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

docSequenceToken对象:

>>> doc[0]
First
>>> doc[1]
,
>>> doc[2]
I
>>> doc[3]
wrote
Run Code Online (Sandbox Code Playgroud)

但它没有单个根令牌.我们解析了由三个句子组成的文本,因此有三个不同的树,每个树都有自己的根.如果我们想从每个句子的根开始解析,首先将有助于将句子作为不同的对象.幸运的是,doc通过该.sents属性向我们公开这些:

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

这些句子中的每一个都Span具有.root指向其根令牌的属性.通常,根令牌将是句子的主要动词(尽管对于不常见的句子结构可能不是这样,例如没有动词的句子):

>>> for sentence in sentences:
...     print(sentence.root)
... 
wrote
parsed
Hooray
Run Code Online (Sandbox Code Playgroud)

找到根令牌后,我们可以通过.children每个令牌的属性向下导航树.例如,让我们在第一句中找到动词的主语和宾语..dep_每个子令牌的属性描述了它与父节点的关系 ; 例如dep_,'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
Run Code Online (Sandbox Code Playgroud)

我们也可以通过查看其中一个令牌的孩子继续沿着树走下去:

>>> list(obj.children)
[some]
Run Code Online (Sandbox Code Playgroud)

因此,使用上面的属性,您可以导航整个树.如果你想用一些依赖树来形象化例句来帮助你理解结构,我建议你用displaCy来玩.


Roh*_*han 8

您可以使用下面的库查看您的依赖树,发现它很有帮助!

from spacy import displacy

nlp = spacy.load('en')
doc = nlp(u'This is a sentence.')
displacy.serve(doc, style='dep')
Run Code Online (Sandbox Code Playgroud)

  • JFI.. 服务选项还会以 Web 链接的形式打开树。对于静态图像(渲染选项可用 `displace.render(doc, style='dep')` (2认同)
  • 要添加到 @prashanth 的评论,您还可以打印到图像(您可以打开/查看,例如在 Firefox 中;请注意,您需要指定完整路径(`/home/victoria/...`,而不是` ~/...`). 代码:`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)` (2认同)

Nic*_*eph 7

事实证明,树可以通过文档中的标记获得.

你想找到树的根,你可以通过文件:

def find_root(docu):
    for token in docu:
        if token.head is token:
            return token
Run Code Online (Sandbox Code Playgroud)

然后,要在树中导航,令牌都有API来通过孩子

  • 一个文件每个句子有1个根 (4认同)

Chr*_*iss 7

我不知道这是一个新的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))
Run Code Online (Sandbox Code Playgroud)

名称print _tree有点用词不当,该方法本身不输出任何内容,而是返回一列字典,每个句子一个。

  • 在v2.1中不推荐使用Doc.print_tree方法,而推荐使用Doc.to_json。 (4认同)

Krz*_*iek 5

我还需要在完整代码下执行此操作:

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)
Run Code Online (Sandbox Code Playgroud)

如果您想为终端设置间距:

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)
Run Code Online (Sandbox Code Playgroud)