【问题标题】:Slow fuzzy matching between two DataFrames两个 DataFrame 之间的慢模糊匹配
【发布时间】:2016-11-25 14:10:47
【问题描述】:

我有带有 cli id 和来源的 DataFrame A (df_cam):

cli id |            origin
------------------------------------
123    | 1234 M-MKT XYZklm 05/2016

和带有快捷方式和活动的 DataFrame B (df_dict)

shortcut |         campaign
------------------------------------
M-MKT    | Mobile Marketing Outbound

我知道,例如来自 1234 M-MKT XYZklm 05/2016 的客户实际上来自活动 Mobile Marketing Outbound,因为它包含关键字 M-MKT

请注意,快捷方式是一个通用关键字,取决于算法应决定的内容。原点也可以是M-MarketingMMKTMob-MKT。我首先通过分析所有来源手动创建了快捷方式列表。我还使用正则表达式在将origin 提取到程序之前对其进行清理。

我想通过快捷方式将客户来源与广告系列匹配并附加分数以查看差异。如下图:

cli id | shortcut |         origin            |        campaign           | Score
---------------------------------------------------------------------------------
123    | M-MKT    | 1234 M-MKT XYZklm 05/2016 | Mobile Marketing Outbound | 0.93

下面是我的程序,它可以运行,但是真的很慢。 DataFrame A 有 ~400.000 行,另一个 DataFrame B 有 ~40 行。

有什么方法可以让它更快吗?

from fuzzywuzzy import fuzz
list_values = df_dict['Shortcut'].values.tolist()

def TopFuzzMatch(tokenA, dict_, position, value):
    """
    Calculates similarity between two tokens and returns TOP match and score
    -----------------------------------------------------------------------
    tokenA: similarity to this token will be calculated
    dict_a: list with shortcuts
    position: whether I want first, second, third...TOP position
    value: 0=similarity score, 1=associated shortcut
    -----------------------------------------------------------------------
    """
    sim = [(fuzz.token_sort_ratio(x, tokenA),x) for x in dict_]
    sim.sort(key=lambda tup: tup[0], reverse=True)
    return sim[position][value]

df_cam['1st_choice_short'] = df_cam.apply(lambda x: TopFuzzMatch(x['cli_origin'],list_values,0,1), axis=1 )
df_cam['1st_choice_sim'] = df_cam.apply(lambda x: TopFuzzMatch(x['cli_origin'],list_values,0,0), axis=1 )

请注意,我还想计算第二和第三最佳匹配来评估准确性。

编辑

我找到了process.ExtractOne 方法,但速度保持不变。 所以我的代码现在看起来像这样:

def TopFuzzMatch(token, dict_, value):
    score = process.extractOne(token, dict_, scorer=fuzz.token_sort_ratio)
    return score[value]

【问题讨论】:

    标签: python fuzzywuzzy


    【解决方案1】:

    我找到了一个解决方案——在我用正则表达式(没有数字和特殊字符)清理原始列之后,只有几百个重复的不同值,所以我只对这些值计算 Fuzz 算法,这显着缩短了时间。

    def TopFuzzMatch(df_cam, df_dict):
        """
        Calculates similarity bewteen two tokens and return TOP match
        The idea is to do it only over distinct values in given DF (takes ages otherwise)
        -----------------------------------------------------------------------
        df_cam: DataFrame with client id and origin
        df_dict: DataFrame with abbreviation which is matched with the description i need
        -----------------------------------------------------------------------
        """
        #Clean special characters and numbers
        df_cam['clean_camp'] = df_cam.apply(lambda x: re.sub('[^A-Za-z]+', '',x['origin']), axis=1)
    
        #Get unique values and calculate similarity
        uq_origin = np.unique(df_cam['clean_camp'].values.ravel())
        top_match = [process.extractOne(x, df_dict['Shortcut'])[0] for x in uq_origin]
    
        #To DataFrame
        df_match = pd.DataFrame({'unique': uq_origin})
        df_match['top_match'] = top_match
    
        #Merge
        df_cam = pd.merge(df_cam, df_match, how = 'left', left_on = 'clean_camp', right_on = 'unique')
        df_cam = pd.merge(df_cam, df_dict, how = 'left', left_on = 'top_match', right_on = 'Shortcut')
    
        return df_cam
    
    df_out = TopFuzzMatch(df_cam, df_dict)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多