2017-06-21 80 views
0

我想做字符串匹配,並在Python中使用模糊wuzzy帶來匹配id。我的數據集非常龐大,數據集1 = 180萬條記錄,數據集2 = 160萬條記錄。多處理模糊模糊字符串搜索 - python

我試了一下,到目前爲止,

首先我想在Python中使用record linkage包,遺憾的是它跑出來的內存時,它建立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) 

我不知道該怎麼辦那?請指教。提前致謝。

+0

您是否解決了這個問題? –

+0

還沒有。仍在努力。 –

回答

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 

idx是匹配最接近傳遞到extract_oneother的索引。我會建議有一個有意義的索引,以便稍後更容易地加入結果。

關於第二個問題,關於過濾到城市,我會用一個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,唯一的區別是指定一個meta到需要的應用:

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 

這裏是一個筆記本:

我很好奇聽到如何的表現。我假設在模糊wuzzy中完成的實際字符串比較將花費大部分時間,但我很想聽聽在熊貓和dask上花費了多少開銷。確保你有計算Levenshtein距離的C擴展。

+0

感謝您的回覆。我今天會嘗試。我如何平行過程?這兩種方法? –

+1

一切都應該平行。你可能想檢查http://dask.pydata.org/en/latest/dataframe-groupby.html,你不應該溢出到磁盤,所以它可能是好的。您還需要確保Levenshtein距離擴展釋放GIL以進行計算(我不確定它是否如此) – TomAugspurger

+0

另一個錯誤是 - AssertionError:傳遞3列,傳遞數據有2列 - 在此行上 - columns = ['Address1','score','idx'])。我認爲fuzzywuzzy.process.extractOne不返回idx作爲它返回的元組的一部分。你能幫忙嗎? @TomAugspurger –