<p>我想在优秀的公认答案中加上一些例子。在Python2.7中测试。</p>
<h3>解析</h3>
<p>让我们以这个奇怪的名字为例。</p>
<pre><code>name = "THE | big,- Pharma: LLC" # example of a company name
</code></pre>
<p>我们可以从删除法律控制条款(此处为有限责任公司)开始。要做到这一点,有一个很棒的<a href="https://pypi.python.org/pypi/cleanco" rel="noreferrer">cleanco</a>Python库,它确实做到了:</p>
<pre><code>from cleanco import cleanco
name = cleanco(name).clean_name() # 'THE | big,- Pharma'
</code></pre>
<p>删除所有标点:</p>
<pre><code>name = name.translate(None, string.punctuation) # 'THE big Pharma'
</code></pre>
<p>(对于unicode字符串,以下代码可以工作(<a href="https://stackoverflow.com/a/11066687/304209">source</a>,<a href="https://pypi.python.org/pypi/regex/" rel="noreferrer">regex</a>):</p>
<pre><code>import regex
name = regex.sub(ur"[[:punct:]]+", "", name) # u'THE big Pharma'
</code></pre>
<p>使用<a href="http://www.nltk.org/" rel="noreferrer">NLTK</a>将名称拆分为标记:</p>
<pre><code>import nltk
tokens = nltk.word_tokenize(name) # ['THE', 'big', 'Pharma']
</code></pre>
<p>小写所有标记:</p>
<pre><code>tokens = [t.lower() for t in tokens] # ['the', 'big', 'pharma']
</code></pre>
<p>删除停止语。请注意,这可能会导致像<code>On Mars</code>这样的公司出现问题,因为<code>On</code>是一个停止词,所以与<code>Mars</code>不正确匹配。</p>
<pre><code>from nltk.corpus import stopwords
tokens = [t for t in tokens if t not in stopwords.words('english')] # ['big', 'pharma']
</code></pre>
<p>我不包括重音和特殊字符在这里(改进欢迎)。</p>
<h3>匹配</h3>
<p>现在,当我们将所有公司名称映射到标记时,我们希望找到匹配的对。可以说,Jaccard(或Jaro Winkler)的相似性比Levenstein更好,但仍然不够好。原因是它没有考虑到名称中单词的重要性(就像TF-IDF那样)。因此,像“公司”这样的常用词对得分的影响,与可能唯一标识公司名称的词一样大。</p>
<p>为了改进这一点,您可以使用本<a href="http://nadbordrozd.github.io/blog/2016/07/29/datamatching-part-3-match-scoring/" rel="noreferrer">awesome series of posts</a>(不是我的)中建议的名称相似性技巧。下面是一个代码示例:</p>
<pre><code># 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
</code></pre>
<p>使用它,您可以匹配相似度超过特定阈值的名称。作为一种更复杂的方法,您还可以取几个分数(例如,这个唯一性分数,Jaccard和Jaro Winkler)并使用一些标记数据训练一个二元分类模型,在给定分数的情况下,如果候选对匹配与否,该模型将输出。更多关于这个的信息可以在同一篇博文中找到。</p>