4
9

More than 5 years have passed since last update.

Pythonであいまいな住所を補正したい

Posted at

あいまいな住所を補正する

  • 誤字・脱字のある住所情報を補正したい。
  • 番地・マンション名などは対象外

使うもの

ソース

動けばいい方針です

住所マスタ作成

def create_address_master()
    """郵便番号データから住所マスタCSVを作成"""
    zip_file = os.path.join(os.path.dirname(__file__), 'ken_all.zip')
    csv_file = os.path.join(os.path.dirname(__file__), 'KEN_ALL.CSV')
    mst_file = os.path.join(os.path.dirname(__file__), 'addr_mst.csv')

    if not os.path.exists(csv_file) and os.path.exists(zip_file):
        with zipfile.ZipFile(zip_file, 'r') as f:
            f.extractall(os.path.dirname(__file__))

    with open(csv_file, 'r', encoding="shift-jis") as f:
        csv_reader = list(csv.reader(f, delimiter=','))

    result = []
    _tmp = ""
    for v in csv_reader:
        _addr = v[6] + v[7]
        if v[8] == "以下に掲載がない場合":
            v[8] = ""
        elif v[8].find("(") != -1:
            if v[8].find(")") != -1:
                # 閉じ括弧があるので1行完結: "("より前の部分だけ使用する
                # ex) L4
                # print("case1-1: ")
                v[8] = v[8][:v[8].find("(")]
                # print(v[8])
            else:
                # 閉じ括弧がないので、次に閉じ括弧が出て来る行を使用すれば良い
                # ex) L3088
                # print("case1-2: ")
                _tmp = v[8][:v[8].find("(")]
                # print(_tmp)
                continue
        elif v[8].find(")") != -1:
            # 開き括弧がなく閉じ括弧ある = 前の行からの続き、かつこの行で終わり
            # ex) L3090
            # print("case2: ")
            v[8] = _tmp
            _tmp = ""
            # print(v[8])
        elif len(_tmp):
            # 開き括弧も閉じ括弧もないのに _tmp が空でない => 括弧の途中なので不要な行
            # ex) L3089
            # print("case3: ")
            continue
        _addr += v[8]

        # 前の行と同じならスキップ
        if len(result) > 1 and _addr == result[-1]:
            continue

        # print(_addr)
        result.append(_addr)

    with open(mst_file, 'w', encoding="utf-8") as f:
        f.write("\n".join(result))

あいまい検索実行

def complement_address(addr: str) -> str:
    """n-gramであいまい検索"""
    addr_num = re.search("[0-9]", addr)
    word = addr[:addr_num.start()] if addr_num else addr

    n = NGram([word], N=2, warp=3)

    csv_file = os.path.join(os.path.dirname(__file__), 'addr_mst.csv')
    if not os.path.exists(csv_file):
        create_address_master()

    with open(csv_file, 'r', encoding="utf-8") as f:
        addr_mst_str = f.read()

    addr_mst_list = addr_mst_str.split("\n")

    probability = 0.0
    _addr = ""
    for v in addr_mst_list:
        res = n.search(v)
        if len(res) == 0:
            continue

        if probability < res[0][1]:
            probability = res[0][1]
            _addr = v

    # 元データから番地以降を取得
    if addr_num:
        _addr += addr[addr_num.start():]

    return _addr

動作確認

正解例

>>> print(complement_address("木京都豊鳥区河袋2-65-6"))
東京都豊島区池袋9-99-9

不正解例

>>> print(_complement_address("木京都豊鳥区沼袋2-65-6"))
東京都中野区沼袋9-99-9
  • 豊鳥区沼袋 に対して 中野区沼袋, 豊島区池袋 ともに2文字違いなので、先にヒットした結果が表示されている

課題

  • 不一致な文字数が同じ場合の判断をどうするか?
    • 番地の構成から判断?
    • 文字の作りが似ている?
4
9
0

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