【问题标题】:Compare similarity between names比较名称之间的相似性
【发布时间】:2016-11-16 20:24:52
【问题描述】:

我必须根据名称对一些数据进行交叉验证。

我面临的问题是,根据来源,名称略有不同,例如:

L & L AIR CONDITIONING   vs L & L AIR CONDITIONING Service

BEST ROOFING vs ROOFING INC

我有几千条记录,所以手动操作会非常耗时,我想尽可能地自动化这个过程。

由于还有其他单词,因此将名称小写是不够的。

有哪些好的算法可以处理这个问题?

也许可以计算给“INC”或“服务”等词赋予低权重的相关性

编辑:

我试过 difflib 库

difflib.SequenceMatcher(None,name_1.lower(),name_2.lower()).ratio()

我得到了不错的结果。

【问题讨论】:

  • 这是一个非常棘手的问题

标签: python machine-learning nlp


【解决方案1】:

我会使用余弦相似度来达到同样的效果。它会给你一个匹配分数,说明字符串的接近程度。

这里是帮助你的代码(我记得几个月前从 Stackoverflow 本身获得了这段代码 - 现在找不到链接)

import re, math
from collections import Counter

WORD = re.compile(r'\w+')

def get_cosine(vec1, vec2):
    # print vec1, vec2
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])

    sum1 = sum([vec1[x]**2 for x in vec1.keys()])
    sum2 = sum([vec2[x]**2 for x in vec2.keys()])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator

def text_to_vector(text):
    return Counter(WORD.findall(text))

def get_similarity(a, b):
    a = text_to_vector(a.strip().lower())
    b = text_to_vector(b.strip().lower())

    return get_cosine(a, b)

get_similarity('L & L AIR CONDITIONING', 'L & L AIR CONDITIONING Service') # returns 0.9258200997725514

另一个我发现有用的版本稍微基于 NLP,我创作了它。

import re, math
from collections import Counter
from nltk.corpus import stopwords
from nltk.stem.porter import *
from nltk.corpus import wordnet as wn

stop = stopwords.words('english')

WORD = re.compile(r'\w+')
stemmer = PorterStemmer()

def get_cosine(vec1, vec2):
    # print vec1, vec2
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])

    sum1 = sum([vec1[x]**2 for x in vec1.keys()])
    sum2 = sum([vec2[x]**2 for x in vec2.keys()])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator

def text_to_vector(text):
    words = WORD.findall(text)
    a = []
    for i in words:
        for ss in wn.synsets(i):
            a.extend(ss.lemma_names())
    for i in words:
        if i not in a:
            a.append(i)
    a = set(a)
    w = [stemmer.stem(i) for i in a if i not in stop]
    return Counter(w)

def get_similarity(a, b):
    a = text_to_vector(a.strip().lower())
    b = text_to_vector(b.strip().lower())

    return get_cosine(a, b)

def get_char_wise_similarity(a, b):
    a = text_to_vector(a.strip().lower())
    b = text_to_vector(b.strip().lower())
    s = []

    for i in a:
        for j in b:
            s.append(get_similarity(str(i), str(j)))
    try:
        return sum(s)/float(len(s))
    except: # len(s) == 0
        return 0

get_similarity('I am a good boy', 'I am a very disciplined guy')
# Returns 0.5491201525567068

您可以同时调用get_similarity 或get_char_wise_similarity 来查看更适合您的用例的方法。我同时使用了两者——正常相似性来剔除非常接近的相似性,然后在字符方面的相似性来剔除足够接近的相似性。然后剩下的就得手动处理了。

【讨论】:

  • 我尝试了 difflib 库,我得到了不错的结果,你如何将你的函数与这个库进行比较?
【解决方案2】:

您也许可以只使用Levenshtein distance,这是计算两个字符串之间差异的好方法。

【讨论】:

    【解决方案3】:

    您或许可以尝试使用Fuzzy String Matching。您可以使用this Python 库。

    它在内部使用 Levenshtein 距离(由 @user3080953 建议)来计算两个单词/短语之间的相似度。

    fuzz.ratio("hello", "hello")
    Out: 100
    
    fuzz.ratio("L & L AIR CONDITIONING", "L & L AIR CONDITIONING Service")
    Out: 85
    

    您可能会设置一个阈值,超过该阈值您会认为两个单词/短语相似。

    【讨论】:

    • 模糊字符串匹配比 difflib 好在哪里?
    • 是一样的。它只是建立在difflib之上
    【解决方案4】:

    您需要弄清楚名称相似意味着什么。 轻微的拼写差异会很困难 - 我不会专注于此。

    假设您有三种变体:
    - 大写/小写
    - 附加词
    - 标点符号与空格

    我建议将每个字符串拆分为单词,无论它们是否用连字符、空格、句点等分隔。将每个字符串转换为数组,元素为单词,按顺序排列。

    然后让一切都一样。

    下一部分将取决于您的数据。您可以从较长的字符串中删除短词,可以删除某些关键字,您可以检查数组中的大多数长词是否匹配...根据您选择的内容,这可能是计算密集型的。

    我敢肯定,这类事情也有现成的工具。取决于你的目标是什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-06
      • 2021-10-13
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 2022-11-22
      • 2012-12-26
      • 1970-01-01
      相关资源
      最近更新 更多