我不是自然语言编程的学生,但我知道这不是微不足道的 strcmp(n1,n2)。

这是我到目前为止所学到的:

  • 比较个人姓名无法 100% 解决
  • 有一些方法可以达到一定程度的准确性。
  • 答案将是特定于区域设置的,没关系。

我不是在寻找拼写替代品!假设输入的拼写是正确的。

例如,以下所有名称都可以指同一个人:

  • 贝里·察卡拉
  • 伯纳德·察卡拉
  • 贝里·J。察卡拉
  • 贝里·察卡拉

我试图:

  1. 构建(或复制)一个对关系 2 个输入名称进行评分的算法
  2. 找到一个索引方法(对于我的数据库中的名称、哈希表等)

笔记:我的任务不是在文本中查找姓名,而是比较两个姓名。例如

name_compare( "James Brown", "Brown, James", "en-US" ) ---> 99.0%
有帮助吗?

解决方案

我在 Python 中使用 Tanimoto Coefficient 来快速(但不是超级)解决方案:

"""
Formula:
  Na = number of set A elements
  Nb = number of set B elements
  Nc = number of common items

  T = Nc / (Na + Nb - Nc)
"""
def tanimoto(a, b):
    c = [v for v in a if v in b]
    return float(len(c)) / (len(a)+len(b)-len(c))

def name_compare(name1, name2):
    return tanimoto(name1, name2)


>>> name_compare("James Brown", "Brown, James")
0.91666666666666663
>>> name_compare("Berry Tsakala", "Bernard Tsakala")
0.75
>>> 

编辑: 一本好书和有用的书的链接.

其他提示

声音指数 有时用于比较相似的名称。它不处理名字/姓氏排序,但您可能只需让代码查找逗号即可解决该问题。

我们最近一直在不停地做这类工作,我们采取的方法是有一个查找表或别名列表。如果您可以忽略拼写错误/听错/非英语名称,那么困难的部分就被消除了。在您的示例中,我们假设第一个单词和最后一个单词是名字和姓氏。介于两者之间的任何内容都将被丢弃(中间名、姓名缩写)。Berry 和 Bernard 将出现在别名列表中 - 当 Tsakala 与 Berry 不匹配时,我们会翻转词序,然后获得匹配项。

您需要了解的一件事是您正在处理的数据库/人员列表。在英语世界中,中间名的记录不一致。因此,您无法根据中间名或中间名首字母来建立或拒绝匹配。Soundex 不会帮助您处理常见的姓名别名,例如“Dick”和“Richard”、“Berry”和“Bernard”以及可能的“Steve”和“Stephen”。在一些社区中,人们居住在同一地址并且有 2 或 3 代人以相同的名字居住在该地址是很常见的。区分它们的唯一方法是根据出生日期。出生日期可能会或可能不会被记录。如果您有影响力,那么您可能应该强制记录出生日期。许多“人物数据库”要么不记录出生日期,要么出于隐私原因不会透露出生日期。

实际上,人名匹配并不那么复杂。它完全基于所提供数据的质量。实践中发生的情况是,许多记录仍然不匹配 - 即使人类查看它们也无法解决不匹配的问题。人们可能会注意到别名列表中未记录的别名,或者可能能够在互联网上查找此人的详细信息 - 但您不能真正期望您的程序能够做到这一点。

银行、信用评级机构和政府有很多关于我们的详细信息。以前的地址、出生日期等这有助于他们将名字连接起来。但对于我们普通程序员来说,没有灵丹妙药。

当然,分析名称顺序和中间名/首字母缩写的存在是微不足道的,因此看起来真正的挑战是了解通用名称的替代方案。我怀疑这是否可以在不使用某种昵称查找表的情况下完成。 这份清单 是一个很好的起点。它没有将 Bernard 映射到 Berry,但它可能会捕获最常见的情况。也许可以在其他地方找到更详尽的列表,但我绝对认为特定于语言环境的查找表是正确的选择。

我在使用 Tanimoto 使用 utf-8 时遇到了真正的问题。

对于使用变音符号的语言有效的是 difflib.SequenceMatcher()

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top