我在NLTK中使用NER来查找句子中的人员,地点和组织。我能够产生这样的结果:
[(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'
谢谢!
答案 0 :(得分:8)
它看起来很长但是它确实起作用了:
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
[OUT]:
[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican Party', u'ORGANIZATION')]
更多详情:
第一个for-loop"带内存"实现这样的目标:
[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION')]
您将意识到所有名称Enitties将在元组中包含多于2个项目,您想要的是单词作为列表中的元素,即'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'
它有点特别和冗长,但我希望它有所帮助。在这里它是一个功能,祝福圣诞节:
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)
答案 1 :(得分:3)
这实际上是在CoreNLP的下一个版本中,名称为MentionsAnnotator
。它可能无法直接从NLTK获得,除非NLTK人员希望支持它以及标准的斯坦福NER接口。
在任何情况下,目前您都必须复制我已链接到的代码(使用LabeledChunkIdentifier
进行脏工作)或者用Python编写自己的后处理器。
答案 2 :(得分:2)
您可以使用标准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)
表示类型的变化是有道理的,因为你肯定需要用于NER标记的POS标签。
最终结果如下:
(S
(PERSON Andrew/NNP)
is/VBZ
part/NN
of/IN
the/DT
(ORGANIZATION Republican/NNP Party/NNP)
in/IN
(LOCATION Dallas/NNP))
答案 3 :(得分:1)
以下是使用 itertools 的 groupby 迭代器对Stanford NER结果进行分组的另一个简短实现:
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 有两个选项: