使用fuzzywuzzy-python对字符串进行比较和分组的嵌套循环



我正在努力制作一个更快的代码,将类似的产品名称(列"prep"(分组在同一个"中;person_id";并且相同的";TNVED";。所以我的数据帧示例如下:数据帧样本

所以我在IIN_BIN上做了字典,这个字典的关键字是TNVED。键的值也是具有作为group_id的键的字典,其根据与fuzzywuzzy的相似性进行分组。

from fuzzywuzzy import fuzz
import warnings
warnings.filterwarnings("ignore")
length = len(np.unique(df['IIN_BIN'].to_list()))   
t1 = time.time()
amount = 0
dict_main = {}
df['prep']=df['prep'].fillna("")
for BIN in np.unique(df['IIN_BIN'].to_list()):
temp_list_BIN = df[df['IIN_BIN'] == BIN]['TNVED']
dict_pre_main = {}

for tnved in np.unique(temp_list_BIN):
dict_temp = {}
j = 0
df_1_slice = df[df['IIN_BIN'] == BIN]
df_1_slice = df_1_slice[df['TNVED'] == tnved]
df_1_slice.reset_index(inplace = True)
df_1_slice.drop(['index'], axis = 1, inplace = True)
while len(df_1_slice) != 0:
temp_list = []
temp_del_list = []
temp_fuzz_list = []
temp_df = pd.DataFrame(columns = df_1_slice.columns)

for i in range(0, len(df_1_slice)):
fuz_rate = fuzz.token_sort_ratio(
df_1_slice['prep'][0], df_1_slice['prep'][i])
if fuz_rate >=90:
temp_del_list.append(i)
temp_list.append([0,i,fuz_rate])
temp_fuzz_list.append(fuz_rate)
temp_df = temp_df.append(df_1_slice.loc[i])
dict_temp[j] = temp_df
df_1_slice.drop(temp_del_list, axis = 0, inplace = True)
df_1_slice.reset_index(inplace = True)
df_1_slice.drop('index', axis = 1, inplace = True)
j+=1
dict_pre_main[tnved] = dict_temp
dict_main[BIN] = dict_pre_main
time_gone = time.time() - t1
if amount%60 == 0:
print('Percentage of BINs proceeded: ', amount/length,
'%. Time gone from start: ', time_gone, ' s.')
amount+=1

也许有一种更快的方法可以做到这一点,因为那时我不得不将所有这些字典解压到一个dataFrame中,这花了我大约1-2天的时间来处理200万行的数据帧?

t1 = time.time()
temp_list = list(df.columns)
temp_list.append('group_sorted')
concat_full = pd.DataFrame(columns = temp_list)
length = len(dict_main.keys())    
amount = 0
for key_iin in dict_main.keys():
for key_tnved in dict_main[key_iin].keys():
for key_group_number in dict_main[key_iin][key_tnved].keys():
dict_main[key_iin][key_tnved][key_group_number]['group_sorted'] = key_group_number
concat_full = concat_full.append(
dict_main[key_iin][key_tnved][key_group_number])

time_gone = time.time() - t1
if amount%60 == 0:
print('Percentage of BINs proceeded: ', amount/length,
'%. Time gone from start: ', time_gone, ' s.')
amount+=1
concat_full.to_csv('item_desc_fuzzied.csv', index = False)

可能有更快的方法吗?

您使用的是Fuzzywuzzy,由于您抑制了警告,我认为您使用的只是纯Python实现。您应该使用fuzzywuzzy[speedup],或者为了获得更好的性能RapidFuzz(我是作者(。在RapidFuzz中,从转换模糊字符串匹配是有意义的

from fuzzywuzzy import fuzz
for i in range(0, len(df_1_slice)):
fuz_rate = fuzz.token_sort_ratio(
df_1_slice['prep'][0], df_1_slice['prep'][i])
if fuz_rate >=90:
temp_del_list.append(i)
temp_list.append([0,i,fuz_rate])
temp_fuzz_list.append(fuz_rate)
temp_df = temp_df.append(df_1_slice.loc[i])
dict_temp[j] = temp_df

类似

from rapidfuzz import process, fuzz
matches = process.extract(
df_1_slice['prep'][0],
df_1_slice['prep'],
scorer=fuzz.token_sort_ratio,
limit=None,
score_cutoff=90)
for choice, score, index in matches:
temp_del_list.append(index)
temp_list.append([0, index, score])
temp_fuzz_list.append(choice)
temp_df = temp_df.append(df_1_slice.loc[index])
dict_temp[j] = temp_df

process.extract的使用具有以下优点:

  • df_1_slice['prep'][0]只经过一次预处理
  • 更少的函数调用,因为它可以在C/C++中迭代数据系列(Python中的函数调用很慢(
  • 可以用更多的方式对查询进行预处理,例如只对查询中的单词排序一次

请注意,此实现试图保持循环后的最终结果相似,并且可能只是解决方案的一部分。你对熊猫的使用可能会有所改进,但我自己对熊猫不是很熟悉。我注意到的一件事是,有些变量似乎从未被使用过。例如temp_fuzz_list。如果它们真的没有使用过,那么移除它们是有意义的。

最新更新