pandas + Google Maps APIでジオコーディング

久々にジオコーディングの仕事をしているのだけれど、緯度経度の取得(やそれに基づく地域メッシュの算出)はGoogle MapsのAPIでやるのが圧倒的に効率的だということを再確認した。

今回ある業態を対象に解析するにあたり、とりあえず公式ウェブサイトからそれらの一覧(店名)と郵便番号、住所をスクレイピングしてきており、それをどう地域メッシュに変換しようか考えていた。

正直なところ最初はGoogle mapsからスクレイピングしてきちゃおうかなとか考えていたんだけど、スクレイピングは基本的に邪悪だと考えているので、やらなくて済むならやらないに越したことはない。ということでGoogle Cloud PlatformからGeocoding API(Maps APIに含まれる)を使うことにした。

Colabでやるなら、

%pip install -U googlemaps

google-maps-services-pythonを入れる。

あとはGCP上でAPI KEYを発行して、

import googlemaps
gm = googlemaps.Client(key=<YOUR_API_KEY_HERE>)

で立ち上げる。

実際に走らせるときには、

res = gm.geocode('愛知県名古屋市天白区塩釜口1-501')
print(res[0]['geometry']['location'])

とかやればいい感じのが返ってきているのがわかる。

今回は既にpandasのDataFrameで名前と住所が取得されているので、たとえば

def find_latlng(addr):
    res = gm.geocode(addr)
    geo = res[0]['geometry']['location']
    return [geo['lat'], geo['lng']]

こんな感じで関数化して、あとはdfの住所に当てて

df['latlng'] = dt['address'].apply(lambda x: find_latlng(x))

とかで取得すればいい。

やってみて思ったけど、頑張って住所を取得してそれをジオコーディングに突っ込んでも、そうしっかり精度良く緯度経度が返ってこない。正直、店名だけ突っ込んだ方が正確かもしれない。一部のどうも緯度経度がずれるなと思っていたものなんかは住所がニ丁目(カタカナのニ)になっていたりした。勘弁してほしい。

そこから地域メッシュへの変換は、総務省統計局が出している緯度経度からの変換を使って

def convlatlng(lat, lng):
    p, a = divmod(lat * 60, 40)
    q, b = divmod(a, 5)
    r, c = divmod(b*60, 30)
    s, d = divmod(c, 15)
    t, _ = divmod(d, 7.5)

    u    = int(lng - 100)
    f    = lng - 100 - u
    v, g = divmod(f*60, 7.5)
    w, h = divmod(g*60, 45)
    x, i = divmod(h, 22.5)
    y, _ = divmod(i, 11.25)

    m = int(s)*2 + int(x) + 1
    n = int(t)*2 + int(y) + 1

    mesh1 = 100*int(p)+int(u)
    mesh2 = 10*int(q) +int(v)
    mesh0 = 10*int(r) +int(w)
    mesh1_2 = int(m)
    mesh1_4 = int(n)

    mesh = (mesh1, mesh2, mesh0, mesh1_2, mesh1_4)
mesh = convlatlng(lat=35.1538553, lng=136.9682402)
# 5236 57 87 1 4

みたいな感じでできる。

API使用時のエラー

このAPIを使うにあたり

API keys with referer restrictions cannot be used with this API.

というエラーが出ることがある。これはGCPのFAQにもある通り、このAPIの呼び出しにあたってリファラベースの制限がかけられないので、APIの「認証情報」から「アプリケーションの制限」で、以下の画像の通りIPアドレスやサブネット指定で制限をかけてやる必要がある。

ColabのIPアドレスが分からないので

!curl ipecho.net/plain

あたりで取得して、それを指定してやればまあとりあえずこの瞬間は使用できる。(個人的にはこういうAPIのアクセス制限なんかはサブネットなどあまりバッファを広く取る形では指定したくないので、僕自身は使う都度バカみたいにわざわざ設定する)

*ちなみに僕の場合はどうせgeocoding APIしか使わないわけで、その下の「API の制限」で呼び出せるAPIをgeocodingに絞っておくなどした方がよい。変に利便性を優先しようとして権限を広くとってはいけない。