郵便番号から緯度経度を計算

JPからは郵便番号一覧が配布されており、国土交通省からは住所と緯度経度一覧が配布されている。これを合わせて、郵便番号から緯度経度を引けるようにした。国土交通省のデータ方が多いので、マッチングして出た点の緯度経度の平均をとる。

JPのデータを読む関数はこんな感じだ。

def read_zip(file_name):
   # read zipcode data 
   name =["code","zip5","zip7","yomi1","yomi2","yomi3","name1","name2","name3","other1","other2","other3","other4","other5","reason"]
   zipcode = pd.read_csv(file_name, names=name, encoding='cp932')
   
   zipcode = zipcode[ ["zip7","yomi3","name1","name2","name3"] ]
   # extract section
   pat1 = r"(.+)$"
   pattern1 = re.compile(pat1)
   zipcode["大字"] = zipcode["name3"].replace(pattern1, '', regex=True)
   
   # Extract section number 
   pat1 = r"(\d+-\d+チヨウメ)"
   pattern1 = re.compile(pat1)
   zipcode["丁目"] = zipcode["yomi3"].str.extract(pattern1)
   
   return zipcode

Pandasで読んだ後に正規表現で大字と丁目データを追加している。

国土交通省のデータは以下の関数で読む。

def read_df(file_name):
   df = pd.read_csv(file_name, encoding='cp932')
   #  Remove the section number  
   pat2 = r"[一二三四五六七八九十壱弐参拾百千万萬億兆〇]+丁目$"
   pattern2 = re.compile(pat2)
   df["大字"] = df["大字町丁目名"].replace(pattern2, '', regex=True)
   #丁目の番号は大字町丁目コードの下3桁
   df["丁目"] = df["大字町丁目コード"] % 100
   return df

これも正規表現で大字を抽出し、丁目番号をコードから生成しただけだ。

2つのデータをマッチングさせて緯度経度を計算し、郵便番号のデータフレームに保管する。

def compute_lat_lng(zipcode,df):
   # Compute the latitude and longitude for each zipcode using the government database (named df)
   count =0
   lat_column, lng_column = [ ],[ ]
   for row in zipcode.itertuples():
       try:
           cyoume = row.丁目.split("-")
           #print(cyoume)
           start, finish = int(cyoume[0]), int(cyoume[1][:-4]) #start cyoume and finish cyoume 
       except:
           start, finish = 0, 0
       extract = df[ (df["都道府県名"] == row.name1) & (df["市区町村名"]==row.name2) & (df["大字"]==row.大字)]
       if len(extract)==0:
           extract = df[ (df["都道府県名"] == row.name1) & (df["市区町村名"]==row.name2) & (df["大字"]=="大字"+row.大字)]
           
       #print( count, len(extract), start, finish )
       lat_list, lng_list = [ ],[ ]
       if len(extract)>0: #compute the median point 
           for row2 in extract.itertuples():
               if start<finish: #cyoume has a range
                   if start<=row2.丁目 and row2.丁目 <=finish:
                       lat_list.append(row2.緯度)
                       lng_list.append(row2.経度)
               else:
                   lat_list.append(row2.緯度)
                   lng_list.append(row2.経度)
           lat_column.append( sum(lat_list)/len(lat_list) )
           lng_column.append( sum(lng_list)/len(lng_list) )
       else:
           #no coreesponding row in df
           lat_column.append(0.)
           lng_column.append(0.)
       count+=1
   zipcode["latitude"] = pd.Series(lat_column)
   zipcode["longitude"] = pd.Series(lng_column)
   return zipcode

あとは47都道府県のファイル名を入れて回すだけだ。10分くらい回すと出来上がりだ。pickleでzip圧縮で保存すればいつでも使える。数万円で販売している会社もあるようだが、買う人がいるのだろうか?

追記:と思ったら無料で配布している人を見つけた。「時間をかけて」と書いてあったので、上限つきのAPIサービスなどでコツコツ変換したのかもしれない。とは言っても郵便番号の精度はいまいちなので、国土交通省の細かい方のデータを使ってジオコーディングするAPIを作った方が実用的だろう。MapBoxもゼンリンと提携したようなので、使えるようになれば描画と一緒に使った方が早いかもしれない。

この記事が気に入ったらサポートをしてみませんか?