LoginSignup
5
8

More than 5 years have passed since last update.

表記揺れを考慮して、登録した値がマスタに登録されているかをマッチングしてみた

Last updated at Posted at 2018-01-30

登録してあるレコードが、マスタに登録があるかをチェックする要件があったので実装してみました。

完全一致する必要はなかったので、ほどほど合致している値がマスタにあるのかを判定したいときに、今回の用途にバッチリあったライブラリを見つけました。

利用したのはdifflibです。
https://docs.python.jp/3/library/difflib.html#difflib.get_close_matches

SequenceMatcherを利用したマッチング

チェックする対象のデータ

registration.csv
GOOGLE inc
google
COMPANY
google technology

マスタに登録してあるデータ

master.csv
GOOGLE
GOOGLE INC
goo
GOOGLE X
GOOD

ロジック

まず、マスタをリストにします。その後、チェック対象のデータを1つずつループで回して、マスタに当てて、類似度をチェックするロジックです。

from __future__ import with_statement
import difflib
import numpy as np

# マスタデータを内包表記でmasterListに入れる
with open("/Desktop/python/master.csv") as f:
    masterList=[line for line in f]

# チェック対象のデータを1つずつ、マスタデータ全体の値と当てる
with open("/Desktop/python/registration.csv") as f:
    for registrationLine in f:
        # チェック対象のデータ1つに対して、マスタを全ての値の類似度を計算
        # upper()を利用して、大文字小文字の差を無くす
        ratioList = [difflib.SequenceMatcher(None, registrationLine.upper(), masterLine.upper()).ratio() for masterLine in masterList]

        # 類似度が一番大きいデータ値とインデックスを取得する。複数ある場合は先頭の値
        npRatioList = np.array(ratioList)
        maxRatio = max(npRatioList)
        maxRatioIndex = npRatioList.argmax()

        # 類似度が0.8より大の場合はマスタに登録あり、小の場合は登録なし、とする
        if maxRatio > 0.80:
            print("登録あり:" + registrationLine.rstrip() + ":" + masterList[maxRatioIndex].rstrip() + ":" + str(maxRatio)) 
        else:
            print("登録なし:" + registrationLine.rstrip() + ":" + masterList[maxRatioIndex].rstrip() + ":" + str(maxRatio)) 

結果

登録あり:GOOGLE inc:GOOGLE INC:1.0
登録あり:google:GOOGLE:1.0
登録なし:COMPANY:goo:0.333333333333
登録なし:google technology:GOOGLE INC:0.571428571429

思っていた通りの結果になりました。名寄せテーブルなんかも作れそうです。

ただ、仕事で使ったデータでは、いまいちな結果も散見されました。例えば「red engineering」と「blue engineering」は異なる会社ですが、engineeringという長い文字列が一致しているため、類似度が高くなってしまいました。

ちなみにratio()よりも精度が低くて速いquick_ratio()とreal_quick_ratio()があるのですが、これらは精度が低すぎたので使えませんでした。

業務ではこのSequenceMatcherは遅すぎて利用できず、get_close_matchesを利用して解決しました。
データが少なければ、SequenceMatcherでも全然okかと思います。
get_close_matchを使ったロジックは別で書きます。

5
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
8