我想为出色的公认答案添加一些示例。在 Python 2.7 中测试。
解析
让我们以这个奇怪的名字为例。
name = "THE | big,- Pharma: LLC" # example of a company name
我们可以从删除法律控制条款开始(这里是 LLC)。为此,有一个很棒的cleanco Python 库,它可以做到这一点:
from cleanco import cleanco
name = cleanco(name).clean_name() # 'THE | big,- Pharma'
删除所有标点符号:
name = name.translate(None, string.punctuation) # 'THE big Pharma'
(对于 unicode 字符串,以下代码可以代替(source,regex):
import regex
name = regex.sub(ur"[[:punct:]]+", "", name) # u'THE big Pharma'
使用NLTK将名称拆分为标记:
import nltk
tokens = nltk.word_tokenize(name) # ['THE', 'big', 'Pharma']
小写所有标记:
tokens = [t.lower() for t in tokens] # ['the', 'big', 'pharma']
删除停用词。请注意,它可能会导致公司出现问题,例如On Mars
will be wrongly match to Mars
,因为On
是一个停用词。
from nltk.corpus import stopwords
tokens = [t for t in tokens if t not in stopwords.words('english')] # ['big', 'pharma']
我在这里不介绍重音字符和特殊字符(欢迎改进)。
匹配
现在,当我们将所有公司名称映射到令牌时,我们想要找到匹配的对。可以说,Jaccard(或 Jaro-Winkler)的相似性在这项任务中优于 Levenstein,但仍然不够好。原因是它没有考虑名称中单词的重要性(就像 TF-IDF 一样)。因此,像“公司”这样的常用词对分数的影响与可能唯一标识公司名称的词一样大。
为了改进这一点,您可以使用这个很棒的系列文章(不是我的)中建议的名称相似性技巧。这是其中的一个代码示例:
# token2frequency is just a word counter of all words in all names
# in the dataset
def sequence_uniqueness(seq, token2frequency):
return sum(1/token2frequency(t)**0.5 for t in seq)
def name_similarity(a, b, token2frequency):
a_tokens = set(a.split())
b_tokens = set(b.split())
a_uniq = sequence_uniqueness(a_tokens)
b_uniq = sequence_uniqueness(b_tokens)
return sequence_uniqueness(a.intersection(b))/(a_uniq * b_uniq) ** 0.5
使用它,您可以匹配相似度超过某个阈值的名称。作为一种更复杂的方法,您还可以获取多个分数(例如,这个唯一性分数,Jaccard 和 Jaro-Winkler)并使用一些标记数据训练一个二元分类模型,如果给定多个分数,它将输出候选对是否匹配。更多信息可以在同一篇博客文章中找到。