2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Python】住所から郵便番号への変換

Last updated at Posted at 2023-07-08

はじめに

郵便番号を住所に変換するコードはよく見かけますが、住所から郵便番号の変換はあまり参考になる記事がなかったのでプログラムを作成しました。

この記事では作成したコードについての説明を行っています。

作ったもの

作成したコードはgithubに載せてあります。

全体の流れ

下記の流れで処理を行っていきます。

  1. 郵便番号のデータを読み込みを行う
  2. 入力された文字列から家屋番号などを消す
  3. 住所を検索する

使用ライブラリー

  • Pandas
  • unicodedata
  • re

郵便番号のデータを読み込む

データを読み込み、 city列town列 を結合し address列を作成しています。この列は住所を探す時に使用します。

main.py
import pandas as pd
import unicodedata
import re

# 郵便番号の設定
post_df = pd.read_csv('郵便番号.csv',encoding = "shift-jis", header=None, names=['post_code', 'prefecture', 'city', 'town'])
post_df['address'] = post_df['city'] + post_df['town'].fillna('')

データは日本郵便は出しているものを加工して使用しています。

メイン処理

コード全体

main.py
class post_code():
    
    def __init__(self):
        self.post_code= 0
        self.score_dict = {}

    def processing(self, address):
        
        #数字を小文字へ
        address_new = unicodedata.normalize('NFKC', str(address))
        # 丁目の前の漢数字を英数字へ
        address_new = address_new.replace('一丁目', '1丁目').replace('二丁目', '2丁目').replace('三丁目', '3丁目').replace('四丁目', '4丁目').replace('五丁目', '5丁目').replace('六丁目', '6丁目').replace('七丁目', '7丁目').replace('八丁目', '8丁目').replace('九丁目', '9丁目')
        address_new = address_new.replace('-', '').replace('', '')
        # 丁目、番地などを削除
        address_new = re.sub(r"\d+丁目|\d+番地|\d+番|\d+号", "", address_new)
        address_new = re.sub(r"\d+$", "", address_new)
        return address_new
    
    def to_post(self, address):
        
        prefecture = address[:4]
        if '' in prefecture:
            prefecture = re.match(r"^(.+?都)",prefecture).group(1)
        elif '' in prefecture:
            prefecture = re.match(r"^(.+?県)",prefecture).group(1)
        elif '' in prefecture:
            prefecture = re.match(r"^(.+?府)",prefecture).group(1)
        elif '' in prefecture:
            prefecture = re.match(r"^(.+?道)",prefecture).group(1)

        
        choose_df = post_df[post_df['prefecture'] == prefecture]
        address_new = address.replace(prefecture, '')

        for index in choose_df.index:
            text = choose_df['address'].loc[choose_df.index == index]
            text = str(text)
            count = 0
            for word in address_new:

                word= str(word)
                if word in text:
                    count += 1
            self.score_dict[index] = count
            
        # print(sorted(self.score_dict.items(), key=lambda x: x[1], reverse=True))
 
        post_code = choose_df['post_code'].loc[choose_df.index == max(self.score_dict, key=self.score_dict.get)].values[0]
        post_code = str(post_code)
        post_code = post_code[:3] + '-' + post_code[3:]
        return post_code

    def run(self, address):
        address_new = self.processing(address)
        self.post_code = self.to_post(address_new)

        return self.post_code

初期化

検索した住所を入れる post_code と検索時に使用する score_dict を初期化する。

クラス内
def __init__(self):
    self.post_code= 0
    self.score_dict = {}

加工メソッドの説明

ここでは郵便番号を検索する際に必要のない情報を以下の処理によって削除し、返り値としています。

検索には基本的には市区町村までを使いますが、 市によってはその後も必要にる場合があります。

  1. 数字を全て小文字に変換する

  2. 漢数字の丁目を英数字へ変更

  3. ハイフンの削除

  4. 丁目や地番などを数字と共に削除

  5. 消し残しのための数字削除処理

クラス内
def processing(self, address):
        
    #数字を小文字へ
    address_new = unicodedata.normalize('NFKC', str(address))
    # 丁目の前の漢数字を英数字へ
    address_new = address_new.replace('一丁目', '1丁目').replace('二丁目', '2丁目').replace('三丁目', '3丁目').replace('四丁目', '4丁目').replace('五丁目', '5丁目').replace('六丁目', '6丁目').replace('七丁目', '7丁目').replace('八丁目', '8丁目').replace('九丁目', '9丁目')
    address_new = address_new.replace('-', '').replace('', '')
    # 丁目、番地などを削除
    address_new = re.sub(r"\d+丁目|\d+番地|\d+番|\d+号", "", address_new)
    address_new = re.sub(r"\d+$", "", address_new)
    return address_new

検索メソッドの説明

簡単に処理の説明をします。

  1. はじめの4文字を使用して都道府県を探し出し、その値を使用して郵便番号データから完全一致する行を取り出し choose_df に代入する。

  2. prefecture の値を address から消す。

  3. choose_df のaddress列から一つずつ値を取り出し、 address_new と何文字一致しているかを score_dict に格納する。

  4. 最後に score_dict の中で一致した文字数が一番多い行から郵便番号を取り出し、ハイフンを付けて返す。

クラス内
def to_post(self, address):
        
    prefecture = address[:4]
    if '' in prefecture:
        prefecture = re.match(r"^(.+?都)",prefecture).group(1)
    elif '' in prefecture:
        prefecture = re.match(r"^(.+?県)",prefecture).group(1)
    elif '' in prefecture:
        prefecture = re.match(r"^(.+?府)",prefecture).group(1)
    elif '' in prefecture:
        prefecture = re.match(r"^(.+?道)",prefecture).group(1)

    
    choose_df = post_df[post_df['prefecture'] == prefecture]
    address_new = address.replace(prefecture, '')

    for index in choose_df.index:
        text = choose_df['address'].loc[choose_df.index == index]
        text = str(text)
        count = 0
        for word in address_new:

            word= str(word)
            if word in text:
                count += 1
        self.score_dict[index] = count
        
 
    post_code = choose_df['post_code'].loc[choose_df.index == max(self.score_dict, key=self.score_dict.get)].values[0]
    post_code = str(post_code)
    post_code = post_code[:3] + '-' + post_code[3:]
    return post_code

実行メソッド

main.py
def run(self, address):
    address_new = self.processing(address)
    self.post_code = self.to_post(address_new)

    return self.post_code

使用方法

runのに検索した住所を都道府県込みで入力してください。

raku_df = post_code().run('東京都港区白金1-2-3')
print(raku_df)
# '108-0072'

終わりに

Pythonで住所から郵便番号を検索するプログラムを作成しました。
今後の課題として、処理の高速化があります!

初学者のため情報に誤りがある可能せいがあります。
ご了承ください。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?