Вычисление имен Norton Recognizer (NER) в Stanford Nancy из формата NLTK

Я использую NER в NLTK для поиска лиц, мест и организаций в предложениях. Я могу привести результаты следующим образом:

[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] 

Можно ли объединить все вместе, используя это? Я хочу так:

 u'Remaking'/ u'O', u'The'/u'O', (u'Republican', u'Party')/u'ORGANIZATION' 

Благодаря!

4 Solutions collect form web for “Вычисление имен Norton Recognizer (NER) в Stanford Nancy из формата NLTK”

Вы можете использовать стандартный способ NLTK для представления фрагментов, используя nltk.Tree . Это может означать, что вам нужно немного изменить свое представление.

То, что я обычно делаю, представляет собой предложения, помеченные NER, в виде списков триплетов :

 sentence = [('Andrew', 'NNP', 'PERSON'), ('is', 'VBZ', 'O'), ('part', 'NN', 'O'), ('of', 'IN', 'O'), ('the', 'DT', 'O'), ('Republican', 'NNP', 'ORGANIZATION'), ('Party', 'NNP', 'ORGANIZATION'), ('in', 'IN', 'O'), ('Dallas', 'NNP', 'LOCATION')] 

Я делаю это, когда использую внешний инструмент для привязки предложения NER. Теперь вы можете преобразовать это предложение в представление NLTK:

 from nltk import Tree def IOB_to_tree(iob_tagged): root = Tree('S', []) for token in iob_tagged: if token[2] == 'O': root.append((token[0], token[1])) else: try: if root[-1].label() == token[2]: root[-1].append((token[0], token[1])) else: root.append(Tree(token[2], [(token[0], token[1])])) except: root.append(Tree(token[2], [(token[0], token[1])])) return root sentence = [('Andrew', 'NNP', 'PERSON'), ('is', 'VBZ', 'O'), ('part', 'NN', 'O'), ('of', 'IN', 'O'), ('the', 'DT', 'O'), ('Republican', 'NNP', 'ORGANIZATION'), ('Party', 'NNP', 'ORGANIZATION'), ('in', 'IN', 'O'), ('Dallas', 'NNP', 'LOCATION')] print IOB_to_tree(sentence) 

Изменение вида представления имеет смысл, потому что вам наверняка нужны метки POS для тегов NER.

Конечный результат должен выглядеть так:

 (S (PERSON Andrew/NNP) is/VBZ part/NN of/IN the/DT (ORGANIZATION Republican/NNP Party/NNP) in/IN (LOCATION Dallas/NNP)) 

Он выглядит долго, но он делает работу:

 ner_output = [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] chunked, pos = [], "" for i, word_pos in enumerate(ner_output): word, pos = word_pos if pos in ['PERSON', 'ORGANIZATION', 'LOCATION'] and pos == prev_tag: chunked[-1]+=word_pos else: chunked.append(word_pos) prev_tag = pos clean_chunked = [tuple([" ".join(wordpos[::2]), wordpos[-1]]) if len(wordpos)!=2 else wordpos for wordpos in chunked] print clean_chunked 

[вне]:

 [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican Party', u'ORGANIZATION')] 

Больше подробностей:

Первый для цикла «с памятью» достигает чего-то вроде этого:

 [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION')] 

Вы поймете, что все имена Enitties будут содержать более двух элементов в кортеже, и вы хотите, чтобы слова были как элементы в списке, то есть 'Republican Party' в (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION') , поэтому вы сделаете что-то подобное, чтобы получить четные элементы:

 >>> x = [0,1,2,3,4,5,6] >>> x[::2] [0, 2, 4, 6] >>> x[1::2] [1, 3, 5] 

Затем вы также поняли, что последний элемент в корте NE – это тег, который вы хотите, так что вы будете делать `

 >>> x = (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION') >>> x[::2] (u'Republican', u'Party') >>> x[-1] u'ORGANIZATION' 

Это немного ad-hoc и vebose, но я надеюсь, что это поможет. И вот это функция, Благословенное Рождество:

 ner_output = [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] def rechunk(ner_output): chunked, pos = [], "" for i, word_pos in enumerate(ner_output): word, pos = word_pos if pos in ['PERSON', 'ORGANIZATION', 'LOCATION'] and pos == prev_tag: chunked[-1]+=word_pos else: chunked.append(word_pos) prev_tag = pos clean_chunked = [tuple([" ".join(wordpos[::2]), wordpos[-1]]) if len(wordpos)!=2 else wordpos for wordpos in chunked] return clean_chunked print rechunk(ner_output) 

Это на самом деле происходит в следующем выпуске CoreNLP под названием MentionsAnnotator . Скорее всего, он не будет доступен напрямую из NLTK, если только люди NLTK не захотят его поддерживать, а также стандартный интерфейс Stanford NER.

В любом случае, на данный момент вам придется скопировать код, с которым я связан (который использует LabeledChunkIdentifier для грязной работы) или написать собственный постпроцессор в Python.

Вот еще одна краткая реализация для группировки результатов Stanford NER с использованием итератора group itertools :

 def grouptags(tags, ignore="O", join=" "): from itertools import groupby for c,g in groupby(tags, lambda t: t[1]): if ignore is None or c != ignore: if join is None: entity = [e for e,_ in g] else: entity = join.join(e for e,_ in g) yield(c, entity) 

Функция grouptags имеет два варианта:

  • ignore : указать класс, который игнорируется и исключается из вывода (по умолчанию: «O»). Если «Нет», все объекты возвращаются.
  • join : укажите символ, используемый для соединения частей (по умолчанию: «»). Если « Нет» , части возвращаются как список.
Python - лучший язык программирования в мире.