根据数据框中的特定列检测和附加重复项的最快方法

Fastest way to detect and append duplicates base on specific column in dataframe

以下是示例数据:

name         age       gender     school
Michael Z    21        Male       Lasalle
Lisa M       22        Female     Ateneo
James T      21        Male       UP
Michael Z.   23        Male       TUP

这是我需要的预期输出:

name       age     gender     similar name  on_lasalle on_ateneo on_up on_tup
Michael Z  21      Male       Michael Z.    True       False     False True
Lisa M     22      Female                   False      True      False False
James T    21      Male                     False      False     True  False

我一直在尝试在我的 python 脚本中使用 fuzzywuzzy。我得到的数据来自 bigquery,然后我将其转换为 dataframe 以清理一些东西。之后,我将 dataframe 转换为 list of dictionaries.

请注意上面的数据,其中 TUP 的 Michael Z. 被附加到 Lasalle 学校的 Michael Z,因为他们有相似的名字,相似率为 100% fuzz.token_set_ratio

我想要的是根据名称获取所有相似的行并将其附加到我们正在查看的当前字典(包括他们的学校)。

这是根据名称获取相似行的代码和循环:

data_dict_list = data_df.to_dict('records')

for x in range(0, len(data_dict_list)):
    for y in range(x, len(data_dict_list)):
         if not data_dict_list[x]['is_duplicate']:
              similarity = fuzz.token_set_ratiod(data_dict_list[x]['name'], data_dict_list[y]['name'])
                   if similarity >= 90:
                       data_dict_list[x]['similar_names'].update('similar_name': data_dict_list[y]['name'])
                       ...
                       data_dict_list[x]['is_duplicate'] = True

这个脚本的运行速度非常慢,有时我会得到 100,000 多个数据!!!所以它将遍历所有这些数据。

我怎样才能加快这个过程?

建议 pandas 非常感谢,因为我很难弄清楚如何在其中循环数据。

作为第一步,您只需将 fuzzywuzzy 的导入替换为 rapidfuzz:

from rapidfuzz import fuzz

这应该已经大大提高了性能。您可以通过以下方式比较 rapidfuzz 中的完整字符串列表来进一步提高性能:

>> import pandas as pd
>> from rapidfuzz import process, fuzz
>> df = pd.DataFrame(data={'name': ['test', 'tests']})
>> process.cdist(df['name'], df['name'], scorer=fuzz.token_set_ratio, score_cutoff=90)
array([[100,   0],
       [  0, 100]], dtype=uint8)

其中 returns 结果矩阵,其中得分低于 90 的所有元素都设置为 0。对于大型数据集,您可以使用 workers 参数启用多线程:

process.cdist(df['name'], df['name'], workers=-1, scorer=fuzz.token_set_ratio, score_cutoff=90)