为了确定句子中从句的位置并将其剥离出来,需要找到一个成分分析的 parser,本文是对使用这个 parser 的一个具体的说明。使用的工具来自 ACL 2018:Constituency Parsing with a Self-Attentive Encoder

安装

这个工具可以和 SpaCy 及 NLTK 一同使用。但是在尝试工程中发现和 SpaCy 的联动除了一些问题,会返回不知道如何解决的错误,但是 NLTK 则运行正常。这里记录 NLTK 版本的安装和使用方法。

首先,这个模型的运行需要先行下载:

1
2
3
4
5
import nltk
nltk.download('punkt')

import benepar
benepar.download('benepar_en')

但是这个下载速度非常地慢。希望离线下载需要访问上述 GitHub 链接,找到对应的benepar_en2.zip包下载。(不知道为何,找不到 benepar_en 包)。将这个压缩包放置在C:/Users/.../AppData/Roaming/nltk_data/models/下。punkt 包也能通过访问 nltk_data 找到对应的压缩包,不过这个包需要放置在上面文件夹旁的tokenizers文件夹下并解压。

这样就完成了这个模型的安装。如果不存在benepar则可以先 install 一次。

使用

1
2
3
import benepar
import nltk
parser = benepar.Parser("benepar_en")

由于我们使用了 nltk 的方法,所以不需要引入 SpaCy 的文件。上面的代码可以获得一个 parser,这个 parser 可以用来完成成分分析。

1
tree = parser.parse(context)

上述获得的 tree 打印出来效果如下:

Added another executive at a big bank: “We were all a little goosey over the weekend trying to forecast what would happen Monday, but it’s been very quiet.”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
(SINV
(VP (VBN Added))
(NP
(NP (DT another) (NN executive))
(PP (IN at) (NP (DT a) (JJ big) (NN bank))))
(: :)
(`` ``)
(S
(S
(NP (PRP We))
(VP
(VBD were)
(DT all)
(ADJP (DT a) (RB little) (JJ goosey))
(PP (IN over) (NP (DT the) (NN weekend)))
(S
(VP
(VBG trying)
(S
(VP
(TO to)
(VP
(VB forecast)
(SBAR
(WHNP (WP what))
(S
(VP
(MD would)
(VP
(VB happen)
(PRN
(-LRB- -LCB-)
(NP (NNP Monday))
(-RRB- -RCB-)))))))))))))
(, ,)
(CC but)
(S
(NP (PRP it))
(VP (VBZ 's) (VP (VBN been) (ADJP (RB very) (JJ quiet))))))
(. .))

返回的 tree 是nltk.tree的结构,对于每一个 node,其子树或为另一个 node,或者为一个 leaf,一个 leaf 就是一个字符串。可以使用:

1
2
if type(node) == str:
pass

判断对象是一个 node 还是一个 leaf,如果是一个 node,则可以仿照 list 的方式对其进行遍历。此外 tree 结构的每一个 node,对应一个 label,调用的方式为:node.label(),可以获得这个节点的标签,在上面的实例中,”S”就是一个标签,标志着其句子成分。