如何从原始文本中解析姓名

2 投票
2 回答
1958 浏览
提问于 2025-04-18 15:47

我在想有没有人知道一些好的库或者方法,可以从原始文本中提取名字。

比如说,我有一些例子:(注意,有时候名字是大写的,有时候不是)

James Vaynerchuck and the rest of the group will be meeting at 1PM. 
Sally Johnson, Jim White and brad burton. 
Mark angleman Happiness, Productivity & blocks. Mark & Evan at 4pm.

我首先想到的是使用某种词性标注工具(比如Python的NLTK),给所有单词打上标签。然后只保留名词,再把这些名词和一个已知单词的数据库(也就是字典)进行对比,如果在字典里找不到,就可以认为它们是名字。

还有其他的想法是深入研究机器学习,但这可能超出了我目前的需求。

如果你有任何想法、建议或者可以推荐的库,那就太好了。

谢谢!

2 个回答

0

我发现这个库在解析名字方面非常有用:Python Name Parser

它还可以处理格式为“姓,名”的名字。

2

我不明白你为什么觉得需要NLTK才能排除字典里的单词,其实只需要一个简单的字典就可以了(你可能在某个地方安装过,比如/usr/share/dict/words,或者你可以从网上下载一个)。

with open('/usr/share/dict/words') as f:
    dictwords = {word.strip() for word in f}
with open(mypath) as f:
    names = [word for line in f for word in line.rstrip().split()
             if word.lower() not in dictwords]

你的words列表可能会包含名字,但如果是这样的话,它们会以大写字母开头,所以:

    dictwords = {word.strip() for word in f if word.islower()}

或者,如果你想允许使用人名,而不是排除字典里的单词:

with open('/usr/share/dict/propernames') as f:
    namewords = {word.strip() for word in f}
with open(mypath) as f:
    names = [word for line in f for word in line.rstrip().split()
             if word.title() in namewords]

不过,这样做其实并不太有效。看看你例子里的“Jim White”。他的姓肯定会出现在任何字典里,而他的名字在很多地方也会出现(比如“Jim”是“Jimmy”的简写,或者是阿拉伯字母“jīm”的常见罗马化形式等等)。而“Mark”也是一个常见的字典单词。反过来,“Will”是一个非常常见的名字,尽管你想把它当作一个单词,而“Happiness”是一个不太常见的名字,但至少有一些人用这个名字。

所以,要让这个方法稍微有效一点,你可能需要结合多种判断方式。首先,不是每个单词要么总是名字,要么从来不是名字,而是每个单词在某个相关的语料库中被用作名字的概率——比如“White”可能有13.7%的概率是名字,“Mark”是41.3%,“Jim”是99.1%,“Happiness”是0.1%等等。接下来,如果这个单词不是句子的第一个单词,但它是大写的,那么它更有可能是一个名字(具体有多大可能性?我不知道,你需要根据你的具体输入进行测试和调整),而如果是小写的,它就不太可能是名字。你还可以引入更多的上下文——例如,如果你有很多全名,如果某个可能是名字的单词正好出现在一个常见姓氏旁边,那么它更有可能是名字。你甚至可以尝试分析语法(如果有些句子你不想处理也没关系;它们只是不受语法规则的影响),所以如果两个相邻的单词只有在第二个单词是动词的情况下才能构成一个句子,那么它们可能就不是名字,尽管那个第二个单词在其他情况下可能是名词(也是个名字)。还有很多其他的方式可以考虑。

撰写回答