在 Python 中通过模糊字符串匹配匹配 2 个大型 csv 文件
Matching 2 large csv files by Fuzzy string matching in Python
我正在尝试将大约 600,000 个个人姓名(全名)与另一个具有超过 8700 万个观察值(全名)的数据库匹配!
我第一次尝试 fuzzywuzzy 库太慢了,所以我决定使用更快的模块 fuzzyset。假设我有一台足够强大的计算机来将所有数据集加载到内存中,我将使用包含 964 个观测值的测试文件执行以下操作,以匹配 50,000 个观测值:
import time
from cfuzzyset import cFuzzySet as FuzzySet
df1=pd.read_csv(file1,delimiter='|') # test file with 964 observations
df2=pd.read_csv(file2,delimiter='|') # test file with 50,000 observations to be matched against
a=FuzzySet() # allocate the FuzzySet object
for row in file2['name']:
a.add(str(row)) # Fill the FuzzySet object with all names from file2
start_time = time.time() # Start recording the time
dicto={'index':[],'name':[]} # Dictionary where I store the output
for names in file1['f_ofulln']:
dicto['index'].append(a.get(names)[0][0])
dicto['name'].append(a.get(names)[0][1])
print("--- %s seconds ---" % (time.time() - start_time))
>>> --- 39.68284249305725 seconds ---
使用更小的数据集(964 个观测值与 50,000 个观测值匹配),时间为 39 秒。
但是,如果我想在完整数据集上执行此方法,这太慢了。
有人知道如何改善 运行 时间吗?我认为 Cython 是不可能的,因为我已经导入了 fuzzyset 模块
的 Cython 版本
非常感谢,
阿德里安
所以我要回答我自己的问题,因为我找到了一种非常快的方法。
我使用 panda.HDFStore 和 panda.to_hdf 方法以 HDF5 格式保存了两个数据库。
我为姓氏的每个第一个字母保存到一个数据框中。
然后,我基于 python-Levenshtein 模块创建了一个查找最接近匹配的函数(非常快,因为它是用 C 语言编写的)。
最后,我一次发送了 26 个批处理作业,每个姓氏字母一个。这意味着我只匹配姓氏首字母相同的人。
请注意,我还编写了函数来查找与出生年份相差不超过 1 年的最接近匹配项。
编辑:由于有人要求,我在下面提供了我的职能摘要。不幸的是,合并两个数据帧的主要功能太长了,无法发布在这里。
# Needed imports:
from Levenshtein import *
import pandas as pd
# Function that get the closest match of a word in a big list:
def get_closest_match(x, list_strings,fun):
# fun: the matching method : ratio, wrinkler, ... (cf python-Levenshtein module)
best_match = None
highest_ratio = 0
for current_string in list_strings.values.tolist():
if highest_ratio!=1:
current_score = fun(x, current_string)
if(current_score > highest_ratio):
highest_ratio = current_score
best_match = current_string
return (best_match,highest_ratio)
# the function that matches 2 dataframes (only the idea behind, since too long to write everything
dicto={'Index':[],'score':[], ...}
def LevRatioMerge(df1,df2,fun,colname,required=[],approx=[],eps=[]):
# Basically loop over df1 with:
for name in df1.itertuples():
result=get_closest_match(name[YourColnumber],df2[YourColname],fun)
dicto['score'].append(result[1])
dicto['Index'].append(name[0])
...
就是这个想法。希望对您的工作有所启发。
我正在尝试将大约 600,000 个个人姓名(全名)与另一个具有超过 8700 万个观察值(全名)的数据库匹配!
我第一次尝试 fuzzywuzzy 库太慢了,所以我决定使用更快的模块 fuzzyset。假设我有一台足够强大的计算机来将所有数据集加载到内存中,我将使用包含 964 个观测值的测试文件执行以下操作,以匹配 50,000 个观测值:
import time
from cfuzzyset import cFuzzySet as FuzzySet
df1=pd.read_csv(file1,delimiter='|') # test file with 964 observations
df2=pd.read_csv(file2,delimiter='|') # test file with 50,000 observations to be matched against
a=FuzzySet() # allocate the FuzzySet object
for row in file2['name']:
a.add(str(row)) # Fill the FuzzySet object with all names from file2
start_time = time.time() # Start recording the time
dicto={'index':[],'name':[]} # Dictionary where I store the output
for names in file1['f_ofulln']:
dicto['index'].append(a.get(names)[0][0])
dicto['name'].append(a.get(names)[0][1])
print("--- %s seconds ---" % (time.time() - start_time))
>>> --- 39.68284249305725 seconds ---
使用更小的数据集(964 个观测值与 50,000 个观测值匹配),时间为 39 秒。
但是,如果我想在完整数据集上执行此方法,这太慢了。
有人知道如何改善 运行 时间吗?我认为 Cython 是不可能的,因为我已经导入了 fuzzyset 模块
的 Cython 版本非常感谢,
阿德里安
所以我要回答我自己的问题,因为我找到了一种非常快的方法。
我使用 panda.HDFStore 和 panda.to_hdf 方法以 HDF5 格式保存了两个数据库。 我为姓氏的每个第一个字母保存到一个数据框中。 然后,我基于 python-Levenshtein 模块创建了一个查找最接近匹配的函数(非常快,因为它是用 C 语言编写的)。
最后,我一次发送了 26 个批处理作业,每个姓氏字母一个。这意味着我只匹配姓氏首字母相同的人。
请注意,我还编写了函数来查找与出生年份相差不超过 1 年的最接近匹配项。
编辑:由于有人要求,我在下面提供了我的职能摘要。不幸的是,合并两个数据帧的主要功能太长了,无法发布在这里。
# Needed imports:
from Levenshtein import *
import pandas as pd
# Function that get the closest match of a word in a big list:
def get_closest_match(x, list_strings,fun):
# fun: the matching method : ratio, wrinkler, ... (cf python-Levenshtein module)
best_match = None
highest_ratio = 0
for current_string in list_strings.values.tolist():
if highest_ratio!=1:
current_score = fun(x, current_string)
if(current_score > highest_ratio):
highest_ratio = current_score
best_match = current_string
return (best_match,highest_ratio)
# the function that matches 2 dataframes (only the idea behind, since too long to write everything
dicto={'Index':[],'score':[], ...}
def LevRatioMerge(df1,df2,fun,colname,required=[],approx=[],eps=[]):
# Basically loop over df1 with:
for name in df1.itertuples():
result=get_closest_match(name[YourColnumber],df2[YourColname],fun)
dicto['score'].append(result[1])
dicto['Index'].append(name[0])
...
就是这个想法。希望对您的工作有所启发。