使用python将排序列与自身进行模糊匹配

时间:2016-12-03 18:20:51

标签: python

我有一个包含两列的20万行数据集:1 - 唯一的客户ID和地址组合以及2 - 收入。该表按收入排序,目标是通过与自身进行模糊匹配来清理第1列,以检查是否有足够接近的客户地址组合以及更高的收入,可用于替换收入较少的组合,这很可能是拼写差异造成的。

示例:

Output

在上面的例子中,第三行与第一行非常相似,所以我希望它取第一行的值。

我有一个有效的python代码,但它太慢了:

import pandas as pd
import datetime
import time
import numpy as np
from pyxdameraulevenshtein import normalized_damerau_levenshtein_distance, normalized_damerau_levenshtein_distance_ndarray

data = pd.read_csv("CustomerMaster.csv", encoding="ISO-8859-1")

# Create lookup column from the dataframe itself:
lookup_data=data['UNIQUE_ID']
lookup_data=pd.Series.to_frame(lookup_data)

# Start iterating on row by row on lookup data to find the first closest fuzzy match and write that back into dataframe:
    start = time.time()
    for index,row in data.iterrows():
        if index%5000==0:print(index, time.time()-start)
        for index2, row2 in lookup_data.iterrows():
            ratio_val=normalized_damerau_levenshtein_distance(row['UNIQUE_ID'],row2['UNIQUE_ID'])
            if ratio_val<0.15:
                data.set_value(index,'UPDATED_ID',row2['UNIQUE_ID'])
                data.set_value(index,'Ratio_Val',ratio_val)
                break

目前,这种模糊匹配的代码块运行时间太长 - 前15k行大约需要8小时,时间会按预期的速度呈指数级增长。关于如何更有效地编写此代码的任何建议?

2 个答案:

答案 0 :(得分:1)

一个直接建议:由于匹配是对称的,因此您需要将每一行仅匹配尚未匹配的行。重写内部循环以跳过先前访问过的行。例如,添加:

if index2 <= index:
  continue

仅此一项就可以将匹配速度提高2倍。

答案 1 :(得分:0)

我遇到了同样的问题,并通过levenshtein软件包(用于创建距离矩阵)和scikit的DBSCAN来解决,以将相似的字符串聚类,并将相同的值赋给聚类中的每个元素。

您可以在此处查看:https://github.com/ebravofm/e_utils(homog_lev())

>>> from e_utils.utils import clean_df
>>> from e_utils.utils import homog_lev

>>> series
0        Bad Bunny
1         bad buny
2      bag bunny
3            Ozuna
4     De La Ghetto
5      de la geto
6     Daddy Yankee
7      dade yankee
8        Nicky Jam
9        nicky jam
10        J Balvin
11        jbalvin
12          Maluma
13          maluma
14        Anuel AA

>>> series2 = clean_df(series)
>>> series2 = homog_lev(series2, eps=3)
>>> pd.concat([series, series2.str.title()], axis=1, keys=['*Original*', '*Fixed*'])

      *Original*       *Fixed*
0      Bad Bunny     Bad Bunny
1       bad buny     Bad Bunny
2    bag bunny       Bad Bunny
3          Ozuna         Ozuna
4   De La Ghetto  De La Ghetto
5    de la geto   De La Ghetto
6   Daddy Yankee  Daddy Yankee
7    dade yankee  Daddy Yankee
8      Nicky Jam     Nicky Jam
9      nicky jam     Nicky Jam
10      J Balvin      J Balvin
11      jbalvin       J Balvin
12        Maluma        Maluma
13        maluma        Maluma
14      Anuel AA      Anuel Aa