Подтвердить что ты не робот

Поиск главы существительного в NLTK и stanford parse в соответствии с правилами поиска главы NP

Обычно голова nounfrase является существительным, которое является самым правым из NP, как показано ниже. Дерево - это головка родительского NP. Так

            ROOT                             
             |                                
             S                               
          ___|________________________        
         NP                           |      
      ___|_____________               |       
     |                 PP             VP     
     |             ____|____      ____|___    
     NP           |         NP   |       PRT 
  ___|_______     |         |    |        |   
 DT  JJ  NN  NN   IN       NNP  VBD       RP 
 |   |   |   |    |         |    |        |   
The old oak tree from     India fell     down

Out [40]: Дерево ('S', [Дерево ('NP', [Дерево ('NP', [Дерево ('DT', ['The']), Дерево ('JJ', [' old ']), Tree (' NN ', [' oak ']), Tree (' NN ', [' tree '])]), Tree (' PP ', [Tree (' IN ', [' from ' ]), Tree ('NP', [Tree ('NNP', ['India'])])])]), Tree ('VP', [Tree ('VBD', ['fall']), Tree ('PRT', [Tree ('RP', ['down'])])])])

Следующий код на основе java-реализации использует упрощенное правило для поиска главы NP, но мне нужно основываться на rules:

parsestr='(ROOT (S (NP (NP (DT The) (JJ old) (NN oak) (NN tree)) (PP (IN from) (NP (NNP India)))) (VP (VBD fell) (PRT (RP down)))))'
def traverse(t):
    try:
        t.label()
    except AttributeError:
          return
    else:
        if t.label()=='NP':
            print 'NP:'+str(t.leaves())
            print 'NPhead:'+str(t.leaves()[-1])
            for child in t:
                 traverse(child)

        else:
            for child in t:
                traverse(child)


tree=Tree.fromstring(parsestr)
traverse(tree)

Приведенный выше код дает результат:

NP: ['', 'old', 'oak', 'tree', 'from', 'India'] NPhead: Индия NP: ['', 'старый', 'дуб', 'дерево'] NPhead: дерево NP: [ 'Индия'] NPhead: Индия

Хотя теперь он дает правильный результат для данного предложения, но мне нужно включить условие, которое только самое большее существительное извлекается как голова, в настоящее время он не проверяет, было ли оно существительным (NN)

print 'NPhead:'+str(t.leaves()[-1])

Итак, что-то вроде следующего в состоянии np head в приведенном выше коде:

t.leaves().getrightmostnoun() 

Майкл Коллинз (Приложение A) содержит правила поиска главы для Penn Treebank, и, следовательно, нет необходимости, чтобы только самые правые существительное - это голова. Следовательно, вышеуказанные условия должны включать такой сценарий.

В следующем примере, приведенном в одном из ответов:

(NP (NP человек), который дал (NP разговор)) пошел домой

Главным существительным предмета является человек, но последний отпуск node NP - это тот, кто дал разговор.

4b9b3361

Ответ 1

Есть встроенная строка для объекта Tree в NLTK (http://www.nltk.org/_modules/nltk/tree.html), см. https://github.com/nltk/nltk/blob/develop/nltk/tree.py#L541.

>>> from nltk.tree import Tree
>>> parsestr='(ROOT (S (NP (NP (DT The) (JJ old) (NN oak) (NN tree)) (PP (IN from) (NP (NNP India)))) (VP (VBD fell) (PRT (RP down)))))'
>>> for i in Tree.fromstring(parsestr).subtrees():
...     if i.label() == 'NP':
...             print i
... 
(NP
  (NP (DT The) (JJ old) (NN oak) (NN tree))
  (PP (IN from) (NP (NNP India))))
(NP (DT The) (JJ old) (NN oak) (NN tree))
(NP (NNP India))


>>> for i in Tree.fromstring(parsestr).subtrees():
...     if i.label() == 'NP':
...             print i.leaves()
... 
['The', 'old', 'oak', 'tree', 'from', 'India']
['The', 'old', 'oak', 'tree']
['India']

Обратите внимание: это не всегда так, что правое большинство существительное является головным существительным NP, например.

>>> s = '(ROOT (S (NP (NN Carnac) (DT the) (NN Magnificent)) (VP (VBD gave) (NP ((DT a) (NN talk))))))'
>>> Tree.fromstring(s)
Tree('ROOT', [Tree('S', [Tree('NP', [Tree('NN', ['Carnac']), Tree('DT', ['the']), Tree('NN', ['Magnificent'])]), Tree('VP', [Tree('VBD', ['gave']), Tree('NP', [Tree('', [Tree('DT', ['a']), Tree('NN', ['talk'])])])])])])
>>> for i in Tree.fromstring(s).subtrees():
...     if i.label() == 'NP':
...             print i.leaves()[-1]
... 
Magnificent
talk

Возможно, Magnificent может быть главным существительным. Другим примером является то, что NP содержит относительное предложение:

(NP (NP человек), который дал (NP разговор)) пошел домой

Голова существительное субъекта person, но последний отпуск node NP the person that gave the talk равен talk.

Ответ 2

Я искал python script, используя NLTK, который выполняет эту задачу и наткнулся на эту запись. Вот решение, которое я придумал. Это немного шумно и произвольно, и определенно не всегда выбирает правильный ответ (например, для составных существительных). Но я хотел опубликовать его, если бы было полезно, чтобы у других было решение, которое в основном работает.

#!/usr/bin/env python

from nltk.tree import Tree

examples = [
    '(ROOT (S (NP (NP (DT The) (JJ old) (NN oak) (NN tree)) (PP (IN from) (NP (NNP India)))) (VP (VBD fell) (PRT (RP down)))))',
    "(ROOT\n  (S\n    (NP\n      (NP (DT the) (NN person))\n      (SBAR\n        (WHNP (WDT that))\n        (S\n          (VP (VBD gave)\n            (NP (DT the) (NN talk))))))\n    (VP (VBD went)\n      (NP (NN home)))))",
    '(ROOT (S (NP (NN Carnac) (DT the) (NN Magnificent)) (VP (VBD gave) (NP ((DT a) (NN talk))))))'
]

def find_noun_phrases(tree):
    return [subtree for subtree in tree.subtrees(lambda t: t.label()=='NP')]

def find_head_of_np(np):
    noun_tags = ['NN', 'NNS', 'NNP', 'NNPS']
    top_level_trees = [np[i] for i in range(len(np)) if type(np[i]) is Tree]
    ## search for a top-level noun
    top_level_nouns = [t for t in top_level_trees if t.label() in noun_tags]
    if len(top_level_nouns) > 0:
        ## if you find some, pick the rightmost one, just 'cause
        return top_level_nouns[-1][0]
    else:
        ## search for a top-level np
        top_level_nps = [t for t in top_level_trees if t.label()=='NP']
        if len(top_level_nps) > 0:
            ## if you find some, pick the head of the rightmost one, just 'cause
            return find_head_of_np(top_level_nps[-1])
        else:
            ## search for any noun
            nouns = [p[0] for p in np.pos() if p[1] in noun_tags]
            if len(nouns) > 0:
                ## if you find some, pick the rightmost one, just 'cause
                return nouns[-1]
            else:
                ## return the rightmost word, just 'cause
                return np.leaves()[-1]

for example in examples:
    tree = Tree.fromstring(example)
    for np in find_noun_phrases(tree):
        print "noun phrase:",
        print " ".join(np.leaves())
        head = find_head_of_np(np)
        print "head:",
        print head

Для примеров, обсуждаемых в вопросе и в других ответах, это вывод:

noun phrase: The old oak tree from India
head: tree
noun phrase: The old oak tree
head: tree
noun phrase: India
head: India
noun phrase: the person that gave the talk
head: person
noun phrase: the person
head: person
noun phrase: the talk
head: talk
noun phrase: home
head: home
noun phrase: Carnac the Magnificent
head: Magnificent
noun phrase: a talk
head: talk