Разбор нескольких предложений с помощью MaltParser с использованием NLTK

Было много вопросов, связанных с MaltParser и/или NLTK:

Теперь существует более стабилизированная версия API MaltParser в NLTK: https://github.com/nltk/nltk/pull/944, но есть проблемы, когда дело доходит до разбора нескольких предложений в то же время.

Разбор одного предложения за один раз кажется прекрасным:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> print(mp.parse_one(sent).tree())
(pajamas (shot I) an elephant in my)

Но разбор списка предложений не возвращает объект DependencyGraph:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> print(mp.parse_one(sent).tree())
(pajamas (shot I) an elephant in my)
>>> print(next(mp.parse_sents([sent,sent2])))
<listiterator object at 0x7f0a2e4d3d90> 
>>> print(next(next(mp.parse_sents([sent,sent2]))))
[{u'address': 0,
  u'ctag': u'TOP',
  u'deps': [2],
  u'feats': None,
  u'lemma': None,
  u'rel': u'TOP',
  u'tag': u'TOP',
  u'word': None},
 {u'address': 1,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 2,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'I'},
 {u'address': 2,
  u'ctag': u'NN',
  u'deps': [1, 11],
  u'feats': u'_',
  u'head': 0,
  u'lemma': u'_',
  u'rel': u'null',
  u'tag': u'NN',
  u'word': u'shot'},
 {u'address': 3,
  u'ctag': u'AT',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'AT',
  u'word': u'an'},
 {u'address': 4,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'elephant'},
 {u'address': 5,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'in'},
 {u'address': 6,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'my'},
 {u'address': 7,
  u'ctag': u'NNS',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NNS',
  u'word': u'pajamas'},
 {u'address': 8,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'Time'},
 {u'address': 9,
  u'ctag': u'NNS',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NNS',
  u'word': u'flies'},
 {u'address': 10,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'like'},
 {u'address': 11,
  u'ctag': u'NN',
  u'deps': [3, 4, 5, 6, 7, 8, 9, 10],
  u'feats': u'_',
  u'head': 2,
  u'lemma': u'_',
  u'rel': u'dep',
  u'tag': u'NN',
  u'word': u'banana'}]

Почему использование parse_sents() не возвращает итерабельность parse_one?

Я мог, однако, просто лениться и делать:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent1 = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> sentences = [sent1, sent2]
>>> for sent in sentences:
>>> ...    print(mp.parse_one(sent).tree())

Но это не то решение, которое я ищу. Мой вопрос заключается в том, как ответить, почему parse_sent() не возвращает итерабельность parse_one(). и как это можно было бы зафиксировать в коде NLTK?


После того, как @NikitaAstrahantsev ответил, я попробовал, что он выводит дерево разбора сейчас, но кажется, что он запутан и помещает оба предложения в один, прежде чем разбирать его.

# Initialize a MaltParser object with a pre-trained model.
mp = MaltParser(path_to_maltparser=path_to_maltparser, model=path_to_model) 
sent = 'I shot an elephant in my pajamas'.split()
sent2 = 'Time flies like banana'.split()
# Parse a single sentence.
print(mp.parse_one(sent).tree())
print(next(next(mp.parse_sents([sent,sent2]))).tree())

[выход]:

(pajamas (shot I) an elephant in my)
(shot I (banana an elephant in my pajamas Time flies like))

Из кода кажется что-то странное: https://github.com/nltk/nltk/blob/develop/nltk/parse/api.py#L45

Почему абстрактный класс парсера в NLTK использует два предложения в одном перед парсингом? Я неправильно вызываю parse_sents()? Если да, то каков правильный способ вызова parse_sents()?

Ответ 1

Как я вижу в ваших примерах кода, вы не вызываете tree() в этой строке

>>> print(next(next(mp.parse_sents([sent,sent2])))) 

когда вы вызываете tree() во всех случаях с помощью parse_one().

В противном случае я не вижу причины, почему это может произойти: parse_one() метод ParserI не переопределяется в MaltParser, и все, что он делает, просто вызывает parse_sents() из MaltParser, см. код.

Обновление: Строка, о которой вы говорите не вызывается, потому что parse_sents() переопределяется в MaltParser и непосредственно вызывается.

Единственное, что у меня есть, это то, что java lib maltparser работает неправильно с входным файлом, содержащим несколько предложений (я имею в виду этот блок - где java запущен). Возможно, исходный анализатор солода изменил формат, и теперь это не '\n\n'. К сожалению, я не могу запустить этот код самостоятельно, потому что maltparser.org не работает на второй день. Я проверил, что входной файл имеет ожидаемый формат (предложения разделены двойной конечной точкой), поэтому очень маловероятно, что оболочка python объединяет предложения.