3

我正在尝试在 python 中使用模糊 wuzzy 进行字符串匹配并带来匹配 id。我的数据集很大,dataset1 = 180 万条记录,dataset2 = 160 万条记录。

到目前为止我尝试过的,

首先我尝试record linkage在python中使用包,不幸的是它在构建时内存不足multi index,所以我以良好的机器能力转移到AWS并成功构建它,但是当我尝试对其进行比较时,它永远运行,我同意其由于比较的数量。

然后,我尝试fuzzy wuzzy使用包进行字符串匹配并并行化该过程dask。并在样本数据上执行它。它工作正常,但我知道这个过程仍然需要时间,因为搜索空间很宽。我正在寻找一种在这段代码上添加阻塞或索引的方法。

test = pd.DataFrame({'Address1':['123 Cheese Way','234 Cookie Place','345 Pizza Drive','456 Pretzel Junction'],'city':['X','U','X','U']}) 
test2 = pd.DataFrame({'Address1':['123 chese wy','234 kookie Pl','345 Pizzza DR','456 Pretzel Junktion'],'city':['X','U','Z','Y'] , 'ID' : ['1','3','4','8']}) 

在这里,我正在尝试寻找test.Address1test2.Address1带来它的ID.

def fuzzy_score(str1, str2):
    return fuzz.token_set_ratio(str1, str2)

def helper(orig_string, slave_df):
    slave_df['score'] = slave_df.Address1.apply(lambda x: fuzzy_score(x,orig_string))
    #return my_value corresponding to the highest score
    return slave_df.ix[slave_df.score.idxmax(),'ID']

dmaster = dd.from_pandas(test, npartitions=24)
dmaster = dmaster.assign(ID_there=dmaster.Address1.apply(lambda x: helper(x, test2)))
dmaster.compute(get=dask.multiprocessing.get)

这很好用,但是我不确定如何通过限制同一城市的搜索空间来对其应用索引。

可以说,我正在根据原始字符串的城市在城市字段和子集上创建一个索引,并将该城市传递给辅助函数,

# sort the dataframe
test2.sort_values(by=['city'], inplace=True)
# set the index to be this and don't drop
test2.set_index(keys=['city'], drop=False,inplace=True)

我不知道该怎么做?请指教。提前致谢。

4

2 回答 2

1

我更喜欢使用fuzzywuzzy.process.extractOne. 将字符串与可迭代的字符串进行比较。

def extract_one(col, other):
    # need this for dask later
    other = other.compute() if hasattr(other, 'compute') else other
    return pd.DataFrame([process.extractOne(x, other) for x in col],
                        columns=['Address1', 'score', 'idx'],
                        index=col.index)

extract_one(test.Address1, test2.Address1)

               Address1  score  idx
0          123 chese wy     92    0
1         234 kookie Pl     83    1
2         345 Pizzza DR     86    2
3  456 Pretzel Junktion     95    3

idxother传递给extract_one最匹配的索引。我建议有一个有意义的索引,以便以后更容易加入结果。

对于您的第二个问题,关于过滤到城市,我会使用 groupby 并申请

gr1 = test.groupby('city')
gr2 = test2.groupby("city")

gr1.apply(lambda x: extract_one(x.Address1, 
gr2.get_group(x.name).Address1))

               Address1  score  idx
0          123 chese wy     92    0
1         234 kookie Pl     83    1
2         345 Pizzza DR     86    2
3  456 Pretzel Junktion     95    3

与 dask 的唯一区别是需要为metaapply 指定 a:

ddf1 = dd.from_pandas(test, 2)
ddf2 = dd.from_pandas(test2, 2)

dgr1 = ddf1.groupby('city')
dgr2 = ddf2.groupby('city')

meta = pd.DataFrame(columns=['Address1', 'score', 'idx'])
dgr1.apply(lambda x: extract_one(x.Address1, 

dgr2.get_group(x.name).Address1),
               meta=meta).compute()

             Address1  score  idx
city                             
U    0  234 kookie Pl     83    1
     1  234 kookie Pl     28    1
X    0   123 chese wy     92    0
     1   123 chese wy     28    0

这是一个笔记本:https ://gist.github.com/a932b3591346b898d6816a5efc2bc5ad

我很想知道性能如何。我假设在fuzzy wuzzy 中完成的实际字符串比较将花费大部分时间,但我很想知道在pandas 和dask 中花费了多少开销。确保您有用于计算 Levenshtein 距离的 C 扩展。

于 2017-06-21T16:43:16.697 回答
1

我曾经遇到过同样的问题。整个过程需要很长时间,即使你会使用多处理,它也不会真的很快。导致速度慢的主要问题是模糊匹配,因为处理非常繁琐且需要大量时间。

或者,在我看来更有效的方法是使用嵌入(也称为词袋)并在其上应用 ML 方法。您将使用数值向量这一事实使整个过程更快!

于 2018-07-05T13:23:07.140 回答