2017-06-21 31 views
0

私は文字列のマッチングを行い、pythonであいまいな曖昧さを使って一致IDを取得しようとしています。私のデータセットは膨大で、dataset1 = 180万レコード、dataset2 = 160万レコードです。 、私がこれまで試したどのような マルチプロセッシングファジー曖昧な文字列検索 - python

まず私はそれがmulti indexを構築する際に、残念ながら、それはメモリ不足、Pythonでrecord linkageパッケージを使用してみましたので、私は良いマシンパワーを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']}) 

、私はtest2.Address1test.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を使用することをお勧めします。これは文字列とiterableの文字列を比較します。 idx

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 

は、最も近い一致するextract_oneに渡さotherの指標です。意味のあるインデックスを持つことをお勧めします。あなたの2番目の質問については

、都市へのフィルタリングについて、私は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 

ここにノートブックがあります:

私はパフォーマンスがどのように聞こえるか分かります。私は実際の文字列の比較があいまいな曖昧さの中で行われたと仮定していますが、時間の大半を取るでしょうが、私はファンダスとdaskにどれくらいのオーバーヘッドが費やされているかを聞きたいと思います。 Levenshtein距離を計算するためのC拡張があることを確認してください。

+0

お返事ありがとうございます。私は今日それを試してみる。どのようにプロセスを並列化するのですか?両方の方法? –

+1

すべてを並列化する必要があります。あなたはhttp://dask.pydata.org/en/latest/dataframe-groupby.htmlをチェックしたいかもしれませんが、ディスクに流出させる必要はないのでOKかもしれません。また、Levenshtein distance extensionがGILを解放していることを確認する必要があります(私にはわかりません) – TomAugspurger

+0

そして、別のエラーがあります - AssertionError:3列が渡され、2行が渡されたデータ - この行に - columns = ['Address1'、 'score'、 'idx'])。私はfuzzywuzzy.process.extractOneが返すタプルの一部としてidxを返さないと思います。あなたはこれを助けてくれますか? @TomAugspurger –