0

2つのcsvファイルがあります。最初の、inputは、さまざまなエラーのある入力番地で構成されています。2つ目refは、きれいな住所表です。内のレコードは、内のレコードinputと一致する必要がありますref。ファイルを一意のレコードを持つリストに変換するのは高速ですが、照合プロセスに到達すると、正規表現なしで内inputの2つのアドレスを照合するだけで85秒かかるため、非常に遅くなります。refの大きさを実感しますrefここでの問題です。長さは100万レコードを超え、ファイルサイズは30MBです。この種のサイズではパフォーマンスの問題が発生することが予想されていましたが、2つのレコードだけにこれだけ長くかかることは許容できません(実際には、最大10,000レコード以上を一致させる必要がある場合があります。さらに、最終的には、refアイテムに正規表現を埋め込む必要があります。より柔軟なマッチングを可能にします。新しい正規表現モジュールのテストはさらに悪く、同じ2つのレコードに対してなんと185秒かかりinputます。大幅に高速化する最善の方法を知っている人はいますか?たとえば、郵便番号でインデックスを作成できますか?

次に、inputとrefからのサンプルアドレスをそれぞれ示します(前処理後)。

60651 N SPRINGFIELD AVE CHICAGO
60061 BROWNING CT VERNON HILLS

これが私がこれまでに持っているものです。(初心者なので、コードにはおそらくあらゆる種類の非効率性があることを認識していますが、それは問題ではありません):

import csv, re

f = csv.reader(open('/Users/benjaminbauman/Documents/inputsample.csv','rU'))

columns = zip(*f)

l = list(columns)

inputaddr = l[0][1:]

f = csv.reader(open('/Users/benjaminbauman/Documents/navstreets.csv','rU'))
f.next()

reffull = []
for row in f:
    row = str(row[0:7]).strip(r'['']').replace("\'","")
    if not ", , , , ," in row: reffull.append(row) 

input = list(set(inputaddr))

ref1 = list(set(reffull))
ref2 = ref1

input_scrub = []
for i in inputaddr:
    t = i.replace(',',' ')
    input_scrub.append(' '.join(t.split()))

ref_scrub = []

for i in ref1:
    t = i.replace(',',' ')
    ref_scrub.append(' '.join(t.split()))

output_iter1 = dict([ (i, [ r for r in ref_scrub if re.match(r, i) ]) for i in input_scrub ])

unmatched_iter1 = [i for i, j in output_iter1.items() if len(j) < 1]
matched_iter1 = {i: str(j[0][1]).strip(r'['']') for i, j in output_iter1.items() if len(j) is 1}
tied_iter1 = {k: zip(*(v))[1] for k,v in output_iter1.iteritems() if len(v) > 1}
4

2 に答える 2

1

新しいモジュールのファジー正規表現の代わりに、実行時間が許容できる場合は、difflibモジュールを使用できます。

import difflib


REF = ['455 Gateway Dr, Brooklyn, NY 11239',
       '10 Devoe St, Brooklyn, NY 11211',
       '8801 Queens Blvd, Elmhurst, NY 11373 ',
       '342 Wythe Ave, Brooklyn, NY 11249 ',
       '4488 E Live Oak Ave, Arcadia, CA 91006',
       '1134 N Vermont Ave, Los Angeles, CA 90029',
       '1101 17th St NW, Washington, DC 20036 ',
       '3001 Syringa St, Hopeful-City, AL 48798',
       '950 Laurel St, Minneapolis, KS 67467']


INPUT = ['4554 Gagate Dr, Brooklyn, NY 11239',
         '10 Devoe St, Brooklyn, NY 11211',
         '8801 Queens Blvd, Elmhurst, NY 11373 ',
         '342 Wythe Ave, Brooklyn, NY 11249 ',
         '4488 E Live Oak Ave, Arcadia, CA 91006',
         '1134 N Vermont Ave, Los Angeles, CA 90029',
         '1101 17th St NW, Washington, DC 20036 ',
         '3001 Syrinuy St, Hopeful Dam, AL 48798',
         '950 Laurel St, Minneapolis, KS 67467',
         '455 Gateway Doctor, Forgotten Place, NY 11239',
         '10 Devoe St, Brook., NY 11211',
         '82477 Queens Blvd, Elmerst, NY 11373 ',
         '342 Waithe Street, Brooklyn, MN 11249 ',
         '4488 E Live Poke Ave, Arcadia, CA 145',
         '1134 N Vermiculite Ave, Liz Angelicas, CA 90029',
         '1101 1st St NW, Washing, DC 20036 ']


def treatment(inp,reference,crit,gcm = difflib.get_close_matches):
    for input_item in inp:
        yield (input_item,gcm(input_item,reference,1000,crit))


for a,b in treatment(INPUT,REF,0.65):
    print '\n- %s\n     %s' % (a, '\n     '.join(b))

結果は次のとおりです。

- 4554 Gagate Dr, Brooklyn, NY 11239
     455 Gateway Dr, Brooklyn, NY 11239
     342 Wythe Ave, Brooklyn, NY 11249 

- 10 Devoe St, Brooklyn, NY 11211
     10 Devoe St, Brooklyn, NY 11211

- 8801 Queens Blvd, Elmhurst, NY 11373 
     8801 Queens Blvd, Elmhurst, NY 11373 

- 342 Wythe Ave, Brooklyn, NY 11249 
     342 Wythe Ave, Brooklyn, NY 11249 
     455 Gateway Dr, Brooklyn, NY 11239

- 4488 E Live Oak Ave, Arcadia, CA 91006
     4488 E Live Oak Ave, Arcadia, CA 91006

- 1134 N Vermont Ave, Los Angeles, CA 90029
     1134 N Vermont Ave, Los Angeles, CA 90029

- 1101 17th St NW, Washington, DC 20036 
     1101 17th St NW, Washington, DC 20036 

- 3001 Syrinuy St, Hopeful Dam, AL 48798
     3001 Syringa St, Hopeful-City, AL 48798

- 950 Laurel St, Minneapolis, KS 67467
     950 Laurel St, Minneapolis, KS 67467

- 455 Gateway Doctor, Forgotten Place, NY 11239
     455 Gateway Dr, Brooklyn, NY 11239

- 10 Devoe St, Brook., NY 11211
     10 Devoe St, Brooklyn, NY 11211

- 82477 Queens Blvd, Elmerst, NY 11373 
     8801 Queens Blvd, Elmhurst, NY 11373 

- 342 Waithe Street, Brooklyn, MN 11249 
     342 Wythe Ave, Brooklyn, NY 11249 
     455 Gateway Dr, Brooklyn, NY 11239

- 4488 E Live Poke Ave, Arcadia, CA 145
     4488 E Live Oak Ave, Arcadia, CA 91006

- 1134 N Vermiculite Ave, Liz Angelicas, CA 90029
     1134 N Vermont Ave, Los Angeles, CA 90029

- 1101 1st St NW, Washing, DC 20036 
     1101 17th St NW, Washington, DC 20036 
于 2013-02-09T02:49:29.567 に答える
0

なぜその線が私に思い浮かびました

output_iter1 = dict([ (i, [ r for r in ref_scrub if re.match(r, i) ]) for i in input_scrub ])

とても時間がかかっていました。refマッチングプロセスでは、非常に大きなリスト内のすべてのアイテムと、小さなリスト内のアイテムとの一致を検索しますinput。これは、その逆ではありません。ref残念ながら、これらのアイテムはアドレス属性によってトークン化されて簡単に固定できるため、内のアイテムに正規表現を埋め込むことができるように、このように構造化する必要がありました。SQLについての理解が限られていることを考えると、2つの回避策があると思います。最初のものは、eyquemの提案に従って私の最後のコメントで提起されたアイデアを使用することができます。2つ目は、正規表現またはdifflibを使用してより複雑な照合を行う前に、equals toステートメントを使用して都市および郵便番号属性によるルックアップ(インデックス?)を使用できます。

都市と郵便番号の属性がリスト内の個別のアイテムになるように、内のアイテムを分割しました。たとえば、次のようになりinputます。ref

ref ('COVE POINTE CT', 'BLOOMINGTON, 61704')
input ('S EBERHART', 'CHICAGO, 60628')

ref以下では、同じ都市と郵便番号を共有する部分に検索を絞り込むことができます。inputこれにより、1000を超えるレコードを含むファイルの時間の長さが56秒に短縮されます。これは実質的に優れています。

matchaddr = []
refaddr = []
unmatched = []
for i in ref:
    for t in input:
        if t[1] == i[1]:
            if re.match(i[0],t[0]):
                matchaddr.append(t[0] + ', ' + t[1])
                refaddr.append(i[0] + ', ' + i[1]) 

これで、最愛の正規表現を再び使用できるようになりました(式が壊滅的なバックトラックなどの追加の問題を引き起こさないことを保留しています)。また、このコードの速度は、都市と郵便番号の属性と完全に一致するものが最初に見つかるためです。都市や郵便番号との柔軟なマッチングも可能にしようとすると、速度が大幅に犠牲になる可能性があります。残念ながら、その時点に到達する必要があるかもしれません(入力には厄介な都市と郵便番号の属性も含まれています)。

于 2013-02-09T22:33:58.127 に答える