我正在尝试在 Python NLTK 中使用斯坦福命名实体识别器 (NER) 提取人员和组织列表。当我跑步时:
from nltk.tag.stanford import NERTagger
st = NERTagger('/usr/share/stanford-ner/classifiers/all.3class.distsim.crf.ser.gz',
'/usr/share/stanford-ner/stanford-ner.jar')
r=st.tag('Rami Eid is studying at Stony Brook University in NY'.split())
print(r)
输出是:
[('Rami', 'PERSON'), ('Eid', 'PERSON'), ('is', 'O'), ('studying', 'O'),
('at', 'O'), ('Stony', 'ORGANIZATION'), ('Brook', 'ORGANIZATION'),
('University', 'ORGANIZATION'), ('in', 'O'), ('NY', 'LOCATION')]
我想要的是从此列表中提取以下形式的所有个人和组织:
Rami Eid
Sony Brook University
我试图遍历元组列表:
for x,y in i:
if y == 'ORGANIZATION':
print(x)
但是此代码每行只打印每个实体一个:
Sony
Brook
University
真实的数据,一句话可以不止一个组织,一个人,不同实体之间如何划界?
原文由 user1680859 发布,翻译遵循 CC BY-SA 4.0 许可协议
感谢@Vaulstein 发现的 链接,很明显经过训练的斯坦福标注器,作为分布式(至少在 2012 年) 不会分块命名实体。从 接受的答案:
您有以下选择:
收集相同标记词的运行;例如,所有标记为
PERSON
的相邻词应作为一个命名实体一起使用。这很容易,但当然它有时会组合不同的命名实体。 (例如New York, Boston [and] Baltimore
是关于三个城市,而不是一个。) 编辑: 这是 Alvas 的代码在接受的 anwser 中所做的。请参阅下面的更简单的实现。使用
nltk.ne_chunk()
。它不使用 Stanford 识别器,但它使用块实体。 (它是一个 IOB 命名实体标记器的包装器)。想出一种方法,在斯坦福标注器返回的结果之上进行您自己的分块。
为您感兴趣的领域训练您自己的 IOB 命名实体分块器(使用 Stanford 工具或 NLTK 的框架)。如果您有时间和资源正确执行此操作,它可能会给您最好的结果。
编辑: 如果你想要的只是拉出连续命名实体的运行(上面的选项 1),你应该使用
itertools.groupby
:如果
netagged_words
是您问题中的(word, type)
元组的列表,则会产生:再次注意,如果同一类型的两个命名实体紧挨着彼此出现,则此方法会将它们组合起来。例如
New York, Boston [and] Baltimore
大约是三个城市,而不是一个。