緯度経度から距離を算出するPythonのライブラリ ― GeoPy

geopy
geopyPython
+3

「Python 緯度経度 距離」と検索しても良さげなライブラリがなかなか出てきません。
また、緯度経度から距離を算出するには複数の求め方がありますので戸惑う可能性があります。

この記事ではPythonのGeoPyというライブラリを使って、一瞬で正確に緯度経度から距離を求める方法を紹介します。
たぶん最も簡単で高機能な距離算出のライブラリです。

また、地球の楕円体モデルの比較や距離の算出方法も記事の後半で紹介しています。

スポンサーリンク

結論

実は緯度経度から距離を求める方法は奥が深く、話が長くなってしまうため、さっさと実装したい方のために結論ファーストで書きます。
GeoPyというライブラリを使えば一瞬で正確に算出してくれます。

GeoPyとはそもそもジオコーディング用のPythonライブラリです。ジオコーディングとは、地理情報(緯度経度)に他の情報(住所や開店時間)を付加することです。

まずはpip install geopyなどでライブラリをインポートします。
このGeoPyというライブラリを使うと、以下のようにして2点間の距離を求めることができます。

from geopy.distance import geodesic

# (緯度, 経度)
TokyoStation = (35.681382, 139.76608399999998)
NagoyaStation = (35.170915, 136.881537)

dis = geodesic(TokyoStation, NagoyaStation).km

print(dis)
# 267.9938255019848

.kmの部分は.mのように好きな単位に変換することができます。
ここで用いたgeodesicという関数が2点の緯度経度を入力すると、高速・正確に距離を返してくれます。

この関数がどのように距離を算出するのか、地球をどのようにモデル化しているかに関しては以下で詳しく説明します。

スポンサーリンク

地球の楕円体モデル

距離を求めるにあたって地球をどのようにモデル化するか説明しなければなりません。
よく使われる代表的な地球の楕円体モデルは次の2つです。(詳しい説明はWikipediaで。)

  • GRS80 (Geodetic Reference System 1980)
    • 現在の世界の測地系で最もよく使われている。
    • 日本の法律(測量法)でも採用されている。
  • WGS84 (World Geodetic System 1984)
    • GPSで用いられている。
    • GeoPyではこちらが標準となっている。

当然、これらは地球を近似的に模した楕円体モデルであるので誤差が生じます。
また、地球上のどの点をとるかによって精度が変わります。
しかし、これらのモデルは公的にも採用されているモデルですので、心配なく使っても良いでしょう。

本記事ではこれらのモデルを標準として紹介します。

2種類の距離の算出方法

GeoPyではモデル化された地球上の2点間の距離を、

  • 測地線距離
  • 大円距離 (大圏距離)

の2種類で算出できます。

測地線距離

測地線距離とは「地球の楕円体モデルの表面上での最短距離」を表します。

最短距離に収束させるために、GeoPyでは次の2種類の手法が用意されています。

  • Vincenty手法
  • Karney手法

Vincenty法は測地線距離を求める反復計算アルゴリズムです。
対蹠点(180度反対の点)の付近では収束しなかったり、収束が遅かったりします。
さらに、精度も0.2 mmまでとKarney法と比べて悪いです。
したがって、Geopyではこの手法は「古い非推奨の手法」としており、geopy2.0からは削除されるそうです。

Karney法は測地線距離を求める新しいアルゴリズムです。
2013年に発表された比較的新しい手法であるからか、日本語ではあまり記事を見かけません。
ここに論文のリンクを貼り付けておきます。
Vincety法よりも正確で、ロバストで、速いです。
したがって、GeoPyではこの手法をデフォルト手法としています。

では、地球の2つの楕円体モデルGRS80, WGS84をKarney法を使って比較してみましょう。
他のモデルを指定することもできますが、デフォルトはWGS84です。
結果は次のようになります。(東京駅から近い順に有楽町駅、名古屋駅、地球のほぼ反対のリオデジャネイロの3つで比較。単位に注意。)

from geopy.distance import geodesic

# (緯度, 経度)
TokyoStation = (35.681382, 139.76608399999998)
YurakuchoStation = (35.675069, 139.763328)
NagoyaStation = (35.170915, 136.881537)
RiodeJaneiro = (-22.906847, -43.172897)

# WGS84モデル(デフォルト)
dis1 = geodesic(TokyoStation, YurakuchoStation).m
# > Wall time: 206 µs
dis2 = geodesic(TokyoStation, NagoyaStation).km
# > Wall time: 250 µs
dis3 = geodesic(TokyoStation, RiodeJaneiro).km 
# > Wall time: 235 µs

print(dis1)
# 743.5549731990958
print(dis2)
# 267.9938255019848
print(dis3)
# 18560.636425222485

# GRS80モデル
dis4 = geodesic(TokyoStation, YurakuchoStation, ellipsoid='GRS-80').m
# > Wall time: 186 µs
dis5 = geodesic(TokyoStation, NagoyaStation, ellipsoid='GRS-80').km
# > Wall time: 214 µs
dis6 = geodesic(TokyoStation, RiodeJaneiro, ellipsoid='GRS-80').km 
# > Wall time: 240 µs

print(dis4)
# 743.5549731881608
print(dis5)
# 267.9938255031999
print(dis6)
# 18560.63642509158

東京駅と有楽町駅は山手線の隣の駅なので単位をメートルにしてあります。(milesも指定できます。)
2つのモデルGRS80, WGS84は2点間の距離に関わらず、実行時間も算出結果もほとんど変わりませんね!
どちらを用いても全く問題なさそうです。

大円距離

大円距離とは「地球の楕円体モデルを表面上の2点と楕円体の中心点を通る平面で切り取ったときの切り口の弧の長さ」を表します。
より正確な最短距離を返す測地線距離の近似という理解で良いと思います。

GeoPyではWGS84モデルのみ使用できます。
実装例はこちら。

from geopy.distance import great_circle

# (緯度, 経度)
TokyoStation = (35.681382, 139.76608399999998)
YurakuchoStation = (35.675069, 139.763328)
NagoyaStation = (35.170915, 136.881537)
RiodeJaneiro = (-22.906847, -43.172897)

# WGS84モデル
dis1 = great_circle(TokyoStation, YurakuchoStation).m
# > Wall time: 41 µs
dis2 = great_circle(TokyoStation, NagoyaStation).km
# > Wall time: 52 µs
dis3 = great_circle(TokyoStation, RiodeJaneiro).km 
# > Wall time: 30 µs

print(dis1)
# 744.8062679029077
print(dis2)
# 267.44664972375193
print(dis3)
# 18566.566790738878

大円距離は近似計算をしているので測地線距離に収束させるKarney法と比べると、5倍程度は速くなりましたが、算出結果には少しずれがあります。
大量の計算が必要なときは大円距離を使うと良さそうですね。

まとめ

今回は実装が簡単であるGeoPyというライブラリを使い、緯度経度から2点間の距離を求める手法について紹介しました。

地球表面上の距離を求めるのは非常に奥が深く、それ自体が研究にもなっています。
調べてみると他にもたくさんの手法があるみたいです。
暇ができたら調べてみます。

スポンサーリンク
H-MEMO

コメント