システムデザイン部のTです。
早速ですが、住所から座標を調べたいってシチュエーション、エリア別マーケティングなどでよくありますよね?
これ、簡単なようで意外と厄介で、特に量がたくさんある場合やリアルタイム処理をしたい場合は以下のことに気を付けなくてはいけません。
・APIの利用制限(利用間隔、アクセス回数等)
・住所の分割(都道府県 / 市区町村 / 丁目 など)を表記ゆれへの対応込みできるか?
・利用料金
そんなのGoogle MapsのAPIを叩けば一発じゃないか、と思われる方も多いかもしれませんが、商用利用は有料なうえ、利用規約で地図画像の表示も求められます。(そうだ!ダミーサイト作ってそっちに表示させればいい!)
そうでなくともAPIの利用の際は、サーバーへのアクセス集中による負荷を避けるために、アクセス間隔や回数に制限がかかっていることが一般的です。
……かといって、国土交通省HPからインストールできる位置参照データを参照しようとしても、まずは与えられた住所のどこまでが都道府県名、どこまでが市区町村……といった具合で分割をしなくてはなりません。
国土交通省HPにある位置参照データ↓
よくある例として、千葉県市川市市川はどこからどこまでが市か?をどうやってプログラムに自動判定させればよいでしょうか?※注
今回はこうした困難を回避した無料で速く柔軟に対応できるジオコーディング方法として、フリーのpythonパッケージであるpyDAMSをご紹介しようと思います。
pyDAMSとは?
pyDAMSの前に、まずはDAMSについてお話しします。
DAMSとは、東京大学空間情報科学研究センターが開発・提供する位置情報変換パッケージです。
このパッケージは無料で配布されており、商用利用も基本的には自由です。ただしC++で書かれており、今となっては少々使い勝手の悪い面があります。
この点を克服し、pythonで読み込めるようにしたものが、株式会社ホットリンクのR&D部門の開発したpyDAMSです。
ライセンスは本家DAMSに従うので、こちらも自由に商用利用できます。さらに、パッケージなので予測システム等に組み込んで使用でき、APIのようなアクセス制限を受けることもありません。
インストールは上記二つのサイトに従い、以下の順で行えます。
・DAMSを配布サイトから直接ダウンロードし、使用環境でビルドする
・クイックスタートページはバージョン情報が古い点にご注意ください(dams-4.3.3 → dams-4.3.4)。
・githubからpyDAMSをcloneして使用環境に置く
・ビルドしたDAMSに含まれる.soファイルを、cloneしてきたpydamsフォルダに入れる
・pyDAMS開発者ブログではdams.soと書かれていますが、実際はlibdams-4.3.4.soです。
・/dams-4.3.4/lib/.lib/libdams-4.3.4.soにあります。
・pyDAMSをビルドする
・一部cythonで書かれているため、必要に応じてcythonやlibgccなどのインストールが必要になります。
ややこしいのですが、cloneしたpydamsフォルダの中にもう一個同名のpydamsフォルダが存在していて、pythonからimportするのは内側の方のpydamsフォルダ(パッケージ)です。
読み込みを行う.pyファイルやJupyter notebookファイル(.ipynb)と同じ階層に、内側のpydamsパッケージとlibdams-4.3.4.soファイルを置いておきましょう。
(面倒ならば外側のpydamsフォルダが置いてある階層に `cp ./pydams/pydams ./ `で内側のパッケージをコピーしてから、同階層のpythonファイルでimportしてもよいです。pydamsフォルダ内がカオスになりますが…)
インストールしたら以下のように試してみましょう。
例として、弊社の住所をジオコーディングしてみます。
# In[1]
from pydams import DAMS
address_here = “東京都港区芝公園1-3-8 苔香園ビル5F”
geocoded_here = DAMS.geocode(address_here)
print(geocoded_here)
# Out[1]
{‘score’: 5,
‘tail’: ‘8 苔香園ビル5F’,
‘candidates’: [[{‘level’: 1,
‘x’: 139.69163513183594,
‘y’: 35.68949890136719,
‘name’: ‘東京都’},
{‘level’: 3, ‘x’: 139.75155639648438, ‘y’: 35.65850067138672, ‘name’: ‘港区’},
{‘level’: 5,
‘x’: 139.75172424316406,
‘y’: 35.65782928466797,
‘name’: ‘芝公園’},
{‘level’: 6,
‘x’: 139.75172424316406,
‘y’: 35.65782928466797,
‘name’: ‘一丁目’},
{‘level’: 7,
‘x’: 139.75155639648438,
‘y’: 35.659645080566406,
‘name’: ‘3番’}]]}
このように、辞書型とリストが入れ子になったオブジェクトが返ってきます。
‘candidates’キーで該当する住所の候補がリスト得られ、
さらにその中に辞書型で住所の詳細levelに応じた経度(x)と緯度(y)が格納されています。
今回は住所候補が一通りに絞られているので、以下のようにして最も詳細な番地までの座標情報を取得します。
# 経度
longitude_here = geocoded_here[‘candidates’][0][-1][‘x’]
# 緯度
latitude_here = geocoded_here[‘candidates’][0][-1][‘y’]
特徴
まずは速さ。このパッケージを使って3万行程のアドレスリストをGoogle Cloud Platform (GCP)上で処理してみたところ、12秒程度で座標を取得することができました。
超速爆速とまでは行きませんが、1リクエストにつき数秒間を空けないといけないAPIに比べればその差は歴然です。
では、どれくらい正確に位置情報を取得できているのでしょうか?
冒頭でも触れた国土交通省が配布する位置情報データを使って試してみたいと思います。
群馬県を例に、ダウンロードサービスページから県内全域の「大字・町丁目レベル」までの位置情報を.csvファイルで取得してきます。
群馬県であることに特に深い意味はありません。
これをテストデータとして、
・pyDAMSでは読み込めない地区が存在しないか
・pyDAMSによって得られた座標が、国土交通省のものからどれだけずれるか
の2点を調べました。
まず1点目ですが、テストデータに掲載された県内の全住所をpyDAMSで読み込むことができました。実用の最低ラインはクリア、というところです。
では、2点目の精度はどうでしょうか?今回は単純にpyDAMS出力値とテストデータ緯度、経度の平方距離で評価しました。
そうしますと、平均的には0.02度程度の誤差でした。1度のずれを100kmとして換算すると、およそ2km、どれくらい正確な情報が欲しいかによりますが、まあまあといったとこでしょうか。
ただし、中には0.1度を越える誤差を示す地区もありました。およそ10kmもずれてしまうことになります。10kmというと、だいたい東京タワーから羽田空港くらいの距離です。
そのような誤差の大きかった地区を以下に示します。
いずれも、市までしかpyDAMSでは絞り込めておらず、町以下が認識されていませんでした。
Wikipedia等で調べてみたところ、これらの町は2005年前後に市町村合併に伴い村から町へと改称していました。
どうやら2005~6年ごろで住所の更新が止まっているらしく、それより新しい情報は含まれていないようです。
最後に表記ゆれへの吸収力を見てみます。
同様の位置情報をAPIの中では利用規約がやや緩いHeartRailsと比較してみたところ……
こちらでは読み込めない地域がいくつか存在しました。具体的には、「群馬県佐波郡玉村町角渕」が挙げられます。
調べてみたところ、HearRailsでは「角渕」ではなく「角淵」として登録されていました。
正式名称はどうやら「角渕」の方らしいのですが、一方のpyDAMSでは両方とも認識することができました。
網羅的には調べられておりませんが、HeartRailsは丁目以下を漢数字でないと読み取ってくれないのに対し、pyDAMSはアラビア文字全角半角でも読み取れたりもするので、
pyDAMSは表記の揺らぎには比較的柔軟に対応してくれるようです。
まとめ
pyDAMSは、住所情報がやや古い代わり、無制限に使えて自動で住所分割もしてくれて、おまけに表記ゆれもある程度吸収してくれます。
例えばリアルタイムで届く顧客情報と座標データとの対応付けを低コストで行いたい、などといったケースでは役に立つかと思います。
※余談ですが、以前とある案件で関西地区のデータを都道府県指定で抽出したところ、なぜか東京のデータが紛れ込んでいました。
なんでかな?と思ってよくよく見たら、「東京都府中市」が「京都府」と見事マッチングして釣り上げられていた、なんてこともありました。
(システムデザイン部:T)