寻找更快的模糊字符串匹配方法

时间:2019-05-27 15:24:21

标签: python pandas fuzzywuzzy

我在python中使用Fuzzywuzzy进行模糊字符串匹配。我在名为HKCP_list的列表中有一组名称,该名称要与pandas列进行迭代匹配,以获取最佳匹配。下面给出的是代码

import fuzzywuzzy
from fuzzywuzzy import fuzz,process

def search_func(row):
    chk = process.extract(row,HKCP_list,scorer=fuzz_token_sort_ratio)[0]
    return chk

wc_df['match']=wc_df['concat_name'].map(search_func)

wc_df数据帧包含“ concat_name”列,该列需要与列表HKCP_list中的每个名称匹配。上面的代码花费了大约2个小时来运行,列表中的名称为6K,“ concat_name”列的名称为11K。

我必须在另一个数据集上重新运行此数据集,列表中的名称为89K,列中的名称为120K。为了加快过程,我在以下关于Stackoverflow的问题中有了一个想法

Vectorizing or Speeding up Fuzzywuzzy String Matching on PANDAS Column

在以上回答的评论之一中,建议比较具有相同第一个字母的名称。我要比较的“ concat_name”列是通过将数据帧中的“ first_name”和“ last_name”列串联而获得的派生列。因此,我正在使用以下函数来匹配第一个字母(由于这是我正在考虑的令牌排序分数,因此我正在将first_name和last_name的第一个字母与列表中的元素进行比较)。下面是代码:

wc_df['first_name_1stletter'] = wc_df['first_name'].str[0]
wc_df['last_name_1stletter'] = wc_df['last_name'].str[0]

import time
start_time=time.time()
def match_func(row):
    CP_subset=[x for x in HKCP_list if x[0]==row['first_name_1stletter'] or x[0]==row['last_name_1stletter']]
    return CP_subset
wc_df['list_to_match']=wc_df.apply(match_func,axis=1)
end_time=time.time()
print(end_time-start_time)

上述步骤耗时1600秒,包含6K X 11K数据。 “ list_to_match”列包含每个concat_name要比较的名称列表。现在在这里,我必须再次使用list_to_match元素,并将单个元素传递到列表中,然后使用process.extract方法进行模糊字符串匹配。在与上述相同的步骤中,是否有更优雅,更快捷的方法来做到这一点?

PS:编辑此代码以添加示例,说明列表和dataframe列的外观。

HKCp_list=['jeff bezs','michael blomberg','bill gtes','tim coook','elon musk'] 
concat_name=['jeff bezos','michael bloomberg','bill gates','tim cook','elon musk','donald trump','kim jong un', 'narendra modi','michael phelps']
first_name=['jeff','michael','bill','tim','elon','donald','kim','narendra','michael']
last_name=['bezos','bloomberg','gates','cook','musk','trump','jong un', 'modi','phelps']
import pandas as pd
df=pd.DataFrame({'first_name':first_name,'last_name':last_name,'concat_name':concat_name})

df中“ concat_name”的每一行都必须与HKcp_list的元素进行比较。

PS:今天进行编辑,以反映昨天错过的第二个代码段中的“:”和行

关于, 尼尔维克

2 个答案:

答案 0 :(得分:0)

您可以尝试this function我在另一个答案中写的,不是100%地确定它的速度如何,您可以自己尝试:

from fuzzywuzzy import fuzz
from fuzzywuzzy import process

# Make dataframe out of list
HKCp = pd.DataFrame({'names':HKCp_list})

# Use fuzzy_merge function
fuzzy_merge(df, HKCp, 'concat_name', 'names')

输出

  first_name  last_name        concat_name           matches
0       jeff      bezos         jeff bezos         jeff bezs
1    michael  bloomberg  michael bloomberg  michael blomberg
2       bill      gates         bill gates         bill gtes
3        tim       cook           tim cook         tim coook
4       elon       musk          elon musk         elon musk
5     donald      trump       donald trump                  
6        kim    jong un        kim jong un                  
7   narendra       modi      narendra modi                  
8    michael     phelps     michael phelps                  

注意,您可以使用treshold参数来获得次要匹配项

答案 1 :(得分:0)

下面给出的是我用于使每个实例的列表动态比较的代码:

import fuzzywuzzy
from fuzzywuzzy import fuzz,process

wc_df['first_name_1stletter'] = wc_df['first_name'].str[0]
wc_df['last_name_1stletter'] = wc_df['last_name'].str[0]

import time
start_time=time.time()
def match_func(row):

    CP_subset=[x for x in HKCP_list if x[0]==row['first_name_1stletter'] or x[0]==row['last_name_1stletter']]
    if len(CP_subset)>0:
        chk=process.extract(row['concat_name'],CP_subset,scorer=fuzz.token_sort_ratio)[0]
    else:
        chk = "No item to match"

    return chk

wc_df['match']=wc_df.apply(match_func,axis=1)

end_time=time.time()
print(end_time-start_time)

上面用于6K X 11K比较的代码花费了大约2600秒,而不是问题中发布的第一段代码所花费的7000秒。