2016-07-19 14 views
2

私は、およそ600,000人の名前(氏名)を、8700万人以上の観察(フルネーム)を持つ別のデータベースにほぼ一致させようとしています! fuzzywuzzyライブラリとPythonでのファジー文字列一致による2つの大きなcsvファイルの照合

私の最初の試みは、あまりにも遅かったので、私ははるかに高速であるモジュールfuzzysetを使用することにしました。 (964回の観測が一致はるかに小さいデータセットで

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 --- 

:私はメモリ内のすべてのデータセットをロードするのに十分な強力なコンピュータを持っていると仮定すると、私は50,000の観測と照合する964回の観測のテストファイルに次のことをやっています50,000回の観察に対して)、時間は39秒であった。

ただし、完全なデータセットに対してこのメ​​ソッドを実行する場合、これは遅すぎます。

実行時間を改善する方法を知っている人はいますか?私はすでに私が見つけたので、

多くのおかげで、

エイドリアン

+0

迷惑メールにしないでください! – Olaf

+1

この問題は、それよりもはるかに難しいです。マッチングを実行する前に87Mデータをブロック(またはクラスタリング)する必要があります。私はデータベース内のすべての名前に600kの名前の間のすべての距離を見つけることをお勧めしません。 'dedupe'と呼ばれるPythonライブラリには、ブロック技術の実装がいくつかあります。しかし、あなたが持っているデータセットに拡大するかどうかは分かりません。もう1つの可能性は、ファジー・マッチングを実行する前に、両方のセットに名前をdrop_duplicateすることです。 (私の曖昧な答えには申し訳ありません...) – titipata

+0

おかげで、私は間違いなくマージするデータセットのサイズを減らすためにできるだけ多くの作業を行います。私は、ファジィセットモジュールがはるかに高速であることを発見したので、質問を修正しました。最後に、データフレーム全体をメモリに保存するためのリソースを見つけました。しかし、それでも、最終的な実行時間は数週間で数えられます! –

答えて

1

は、だから私は自分の質問に答えるつもりですfuzzysetモジュールのCython版をインポートしていますので、Cythonは可能性はないと思われますかなり速いです。

panda.HDFStoreおよびpanda.to_hdfメソッドを使用して、両方のデータベースをHDF5形式で保存しました。 姓の最初の文字ごとに1つのデータフレームに保存しました。 次に、Python-Levenshteinモジュールに基づいて最も近い一致を見つける関数を作成しました(C言語でプログラムされているので非常に高速です)。

最後に、私は一度に26のバッチジョブを送信しました.1つは姓の文字ごとです。つまり、私は姓が同じ頭文字の人にしか合致しません。

私はまた、1歳以上の違いがない誕生年と最も近い一致を見つける機能をプログラムしました。

EDIT:要望して以来、私は私の機能の要約を以下に提供しています。 2つのデータフレームをマージする主な機能は、残念ながらここに掲載するには長すぎます。

# 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]) 
     ... 

これは考えです。あなたの仕事に十分なインスピレーションを与えてくれることを願っています。

+0

それほど古くから、私は幾分同じロジックを構築しています。あなたがあなたのpython-Levenshtein関数をどのように書いたのか分かりますか?私はFuzzyWuzzyからのプロセスを使用していて、私のニーズには遅すぎるようです。 – BernardL

+0

私は残念なことに私の機能は非常に長く、本当に私の問題に合わせて、私の答えを編集しました。私はこの小さなサマリーがあなた自身の問題のためにpython-Levenshteinモジュールを使用するのに十分であることを願っています。 –

+0

こんにちは。私はアドレス一致のために同じ論理を実装しようとしています。 "city_name"をブロックまたはインデックスキーとして保持しています。あなたが書いた機能を見ることは可能でしょうか?それは私のために役立つでしょう。 –

関連する問題