首页 > 解决方案 > FuzzyWuzzy 用于 Python 中非常相似的记录

问题描述

我有一个数据集,我想找到最接近的字符串匹配。为此,我以这种方式使用 FuzzyWuzzy

sol=process.extract(t,dev2,scorer=fuzz.token_sort_ratio)

其中 t 是字符串,dev2 是要比较的列表。我的问题是,有时它有非常相似的记录,而 FuzzyWuzzy 提供的选项似乎很缺乏。我已经用 token_sort、token_set、partial_token 排序和设置、ratio、partial_ratio 和 WRatio 进行了测试。

例如,该字符串Italy - Serie A为我提供了以下 2 个最接近的匹配项。

Token_sort_ratio: (92, 'Italy - Serie D');(86, 'Italian - Serie A')

想要的显然是第二个,但逐个字符更接近第一个,这是一个不同的联盟。

这也发生在团队中。如果,假设我有一个字符串Buchtholz,我会Buchtholz II在得到TSV Buchtholz.

我现在的主要猜测是尝试更重地加权几个字符的存在和缺失,比如字符串末尾的单个大写字母,所以如果字母有差异或缺失,它的权重会不那么接近。或 for()和特殊字符。

我不知道是否有办法考虑到这一点,或者你们有更好的方法来获得真正匹配的字符串。

标签: python-3.xfuzzy-search

解决方案


相似性匹配通常需要了解正在分析的数据。即这不仅仅是单轮匹配。我建议你通过更多的匹配步骤来传递你的结果,从具有低截止分数的包容/乐观方法(如 token_set_ratio)开始,并朝着具有更高截止分数的更排斥/悲观方法努力,直到你有一个明确的赢家。如果您对正在分析的文本有更多了解,您甚至可以在进行时修改字符串。

在我处理的一个案例中,我对货物移动描述进行了相似性匹配。在描述中,数字序列比文本更重要。例如,在寻找“SLURRY VALVE 250MM RAGMAX 2000”的匹配项时,字符串的 250 和 2000 部分很重要,否则我会得到“SLURRY VALVE 50MM RAGMAX 2000”作为最佳匹配,而不是“VALVE B/F 250MM,RAGMAX” 250RAG2000 RAGON”这是一个更好的结果。

我把相似度匹配过程分为两个步骤: 1. 使用乐观匹配记分器(token_set_ratio)得到一堆相似匹配 2. 得到这些结果的数字序列,并通过更严格的记分器(token_sort_ratio)进行另一轮匹配)。在上面显示的示例中,这样做给了我更好的结果。

以下是一些可能有帮助的代码块:

这是一个从序列中获取数字的函数。(在您的情况下,您可能会使用它来从字符串中排除数字?)

def get_numbers_from_string(description):   
    numbers = ''.join((ch if ch in '0123456789.-' else ' ') for ch in description)
    numbers = ' '.join([nr for nr in numbers.split()])
    return numbers

这是我用来将描述匹配通过两轮的代码的一部分:

try:    
    # get close match from goods move that has material numbers
    df_material = pd.DataFrame(process.extract(description, 
                                               corpus_material,
                                               scorer=fuzz.token_set_ratio), 
                               columns=['Similar Text','Score']
                              )

    if df_material['Score'][df_material['Score']>=cut_off_accuracy_materials].count()>=1:
        similar_text = df_material['Similar Text'].iloc[0]
        score = df_material['Score'].iloc[0]

        if nr_description_numbers>4:
            # if there are multiple matches found, then get best number combination match  
            df_material = df_material[df_material['Score']>=cut_off_accuracy_materials]
            new_corpus = list(df_material['Similar Text'])
            new_corpus = np.vectorize(get_numbers_from_string)(new_corpus)
            df_material['numbers'] = new_corpus
            df_numbers = pd.DataFrame(process.extract(description_numbers, 
                                                       new_corpus,
                                                       scorer=fuzz.token_sort_ratio), 
                                      columns=['numbers','Score']
                                     )

            similar_text = df_material['Similar Text'][df_material['numbers']==df_numbers['numbers'].iloc[0]].iloc[0]
            nr_score = df_numbers['Score'].iloc[0]

希望它有帮助,祝你好运


推荐阅读