【问题标题】:NLTK separately extract leaves and non-leaf nodesNLTK 分别提取叶子和非叶子节点
【发布时间】:2016-10-19 07:51:58
【问题描述】:

我正在使用Standford Sentiment Treebank 数据集,我正在尝试提取叶子和节点。数据如下

(3 (2 (2 The) (2 Rock)) (4 (3 (2 is) (4 (2 destined) (2 (2 (2 (2 (2 to) (2 (2 be) (2 (2 the) (2 (2 21st) (2 (2 (2 Century) (2 's)) (2 (3 new) (2 (2 ``) (2 Conan)))))))) (2 '')) (2 and)) (3 (2 that) (3 (2 he) (3 (2 's) (3 (2 going) (3 (2 to) (4 (3 (2 make) (3 (3 (2 a) (3 splash)) (2 (2 even) (3 greater)))) (2 (2 than) (2 (2 (2 (2 (1 (2 Arnold) (2 Schwarzenegger)) (2 ,)) (2 (2 Jean-Claud) (2 (2 Van) (2 Damme)))) (2 or)) (2 (2 Steven) (2 Segal))))))))))))) (2 .)))

我想要的东西如下:

i) 带有标签的叶子(uni-gram):

[(2 The), (2 Rock), (2 is), (2 destined),...]

ii) 带有标签的上层节点(bi-gram):

[(2 (2 the) (2 Rock)), (2 (2 ``) (2 Conan)), (2 (2 Century) (2 's)),..] 

直到我到达树的根部。

我尝试使用正则表达式来完成此操作,但无法正确输出。

我拥有的代码(用于 uni-gram):

import re
import nltk

location = '.../NLP/Standford_Sentiment_Tree_Data_Set/' +\
           'trainDevTestTrees_PTB/trees/train.txt'
text = open(location, 'r')

test = text.readlines()[0]
text.close()

uni_regex = re.compile(r'(\([0-4] \w+\))')
temp01 = uni_regex.findall(test)

# bi-gram
bi_regex = re.compile(r'(\([0-4] \([0-4] \w+\) \([0-4] \w+\)\))')
temp02 = bi_regex.findall(test)

以上代码输出:

['(2 The)', '(2 Rock)', '(2 is)', '(2 destined)', '(2 to)', '(2 be)', '(2 the)', '(2 21st)', '(2 Century)', '(3 new)',...]

未能捕获(2 ``)(2 '') 并提取(2 Jean) 而不是(2 Jean-Claude)

输出捕获(2 (2``) (2 Conan))失败

有没有办法使用nltkregex 的某些配置获得我想要的结果,不会错过任何令牌?

我已经查看并尝试修改NLTK tree data structure, finding a node, it's parent or children 中提供的解决方案,但该问题似乎涉及在休假中查找特定单词并显示树结构,而我需要缩进的解决方案类似于以上 n-gram。

【问题讨论】:

    标签: python tree nlp nltk nodes


    【解决方案1】:

    不要在正则表达式上浪费时间,这就是树类的用途。像这样使用 nltk 的 Tree 类:

    mytree = "(3 (2 (2 The) (2 Rock)) (4 (3 (2 is) (4 (2 destined) (2 (2 (2 (2 (2 to) (2 (2 be) (2 (2 the) (2 (2 21st) (2 (2 (2 Century) (2 's)) (2 (3 new) (2 (2 ``) (2 Conan)))))))) (2 '')) (2 and)) (3 (2 that) (3 (2 he) (3 (2 's) (3 (2 going) (3 (2 to) (4 (3 (2 make) (3 (3 (2 a) (3 splash)) (2 (2 even) (3 greater)))) (2 (2 than) (2 (2 (2 (2 (1 (2 Arnold) (2 Schwarzenegger)) (2 ,)) (2 (2 Jean-Claud) (2 (2 Van) (2 Damme)))) (2 or)) (2 (2 Steven) (2 Segal))))))))))))) (2 .)))"
    
    >>> t = nltk.Tree.fromstring(mytree)
    >>> print(t)
    (3
      (2 (2 The) (2 Rock))
      (4
        (3
          (2 is)
          (4
            (2 destined)
            (2
              ...
    

    然后您可以提取和计算叶子,并请求相应的“树位置”(每个叶子的路径,以列表的形式):

    >>> leafpos = [ t.leaf_treeposition(n) for n, x in enumerate(t.leaves()) ]
    >>> print(leafpos[0:3])
    [(0, 0, 0), (0, 1, 0), (1, 0, 0, 0)]
    

    最后,您可以向上遍历树位置以获得所需的单元:由每个叶子正上方的节点支配的子树,每个叶子上方的两个步骤,等等:

    >>> level1_subtrees = [ t[path[:-1]] for path in leafpos ]
    >>> for x in level1_subtrees:
    ...     print(x, end = " ")
    (2 The) (2 Rock) (2 is) (2 destined) (2 to) (2 be) (2 the) ...
    
    >>> level2_subtrees = [ t[path[:-2]] for path in leafpos ]
    

    但是请注意,更高级别的子树并不像您想象的那样。例如,如果您从叶子 3 (destined) 上升两级,您将不会得到“bigram”。您将位于标记为4 的节点上,该节点支配了句子的其余部分。也许您实际上对枚举所有子树感兴趣?在这种情况下,只需遍历t.subtrees()

    如果这不是您想要的,请查看Tree API 并选择另一种方法来选择您需要的部件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-26
      • 2011-02-03
      • 1970-01-01
      • 2020-06-10
      • 1970-01-01
      • 2011-04-22
      相关资源
      最近更新 更多