使用Pyner进行命名实体识别时遇TypeError错误求助
这个错误的根源很明确:PyNER解析邮件文本后,生成的实体对列表里出现了实体类型为None的条目,在排序时None和字符串类型的实体标签(比如PERSON)无法用<比较,触发了类型错误。
从错误栈能看到,问题出在ner/client.py的__collapse_to_dict方法里:当执行sorted(pairs, key=itemgetter(0))时,pairs中的某些元素第一个值(实体类型)是None,而其他元素是字符串,Python不允许None和字符串做大小比较,所以抛出了TypeError: '<' not supported between instances of 'NoneType' and 'str'。
为什么邮件文本会出现这种情况?大概率是邮件里包含PyNER无法正确处理的内容,比如:
- 特殊格式(比如HTML标签、邮件签名里的特殊符号、换行符)
- 非标准的文本结构(比如乱码、缩写、特殊命名)
- 邮件里的空白或无意义内容被错误解析
解决方案
1. 先排查解析后的实体对内容
先手动获取PyNER返回的标记文本,看看具体哪些内容导致了None标签:
tagged_text = tagger.tag_text(firstEmail) print(tagged_text)
然后自己解析成实体对(模仿PyNER的__inlineXML_parse_entities逻辑),就能找到带None的条目,定位邮件里的问题内容。
2. 修改PyNER的__collapse_to_dict方法过滤无效条目
找到你的Python环境里的ner/client.py文件(路径在错误栈里:~/anaconda3/envs/nlp/lib/python3.6/site-packages/ner-0.1-py3.6.egg/ner/client.py),修改__collapse_to_dict方法,在排序前过滤掉实体类型为None的条目:
def __collapse_to_dict(self, pairs): """ Takes list of (tag, entity) pairs, collapses into dict of {tag: [entities]} """ # 先过滤掉实体类型为None的无效条目 filtered_pairs = [pair for pair in pairs if pair[0] is not None] return dict((first, list(map(itemgetter(1), second))) for (first, second) in groupby(sorted(filtered_pairs, key=itemgetter(0)), key=itemgetter(0)))
这样就能避免None参与排序,解决类型错误。
3. 预处理邮件文本
在传入PyNER之前,先清理邮件内容:
- 如果是HTML邮件,用
BeautifulSoup转换成纯文本:from bs4 import BeautifulSoup cleaned_email = BeautifulSoup(firstEmail, "html.parser").get_text() - 去掉多余的换行、制表符、特殊符号:
import re cleaned_email = re.sub(r'\s+', ' ', cleaned_email).strip() - 移除邮件签名、页眉页脚等无关内容,只保留正文部分。
内容的提问来源于stack exchange,提问作者PeachyDinosaur

