Vincentyと大圏距離の計算の違いは?


16

Pythonのgeopyパッケージには、Great CircleVincentyの公式という 2つの距離測定技術が備わっています

>>> from geopy.distance import great_circle
>>> from geopy.distance import vincenty
>>> p1 = (31.8300167,35.0662833) # (lat, lon) - https://goo.gl/maps/TQwDd
>>> p2 = (31.8300000,35.0708167) # (lat, lon) - https://goo.gl/maps/lHrrg
>>> vincenty(p1, p2).meters
429.16765838976664
>>> great_circle(p3, p4).meters
428.4088367903001

違いはなんですか?どの距離測定が望ましいですか?

回答:


18

ウィキペディアによると、Vincentyの式はより遅いがより正確です:

Vincentyの公式は、スフェロイドの表面上の2点間の距離を計算するために測地学で使用される2つの関連する反復法で、Thaddeus Vincenty(1975a)によって開発されました。地球を想定した大圏距離などの方法よりも正確です。

精度の違いは~0.17%、イスラエルの428メートルの距離にあります。私は迅速で汚れた速度テストを行いました:

<class 'geopy.distance.vincenty'>       : Total 0:00:04.125913, (0:00:00.000041 per calculation)
<class 'geopy.distance.great_circle'>   : Total 0:00:02.467479, (0:00:00.000024 per calculation)

コード:

import datetime
from geopy.distance import great_circle
from geopy.distance import vincenty
p1 = (31.8300167,35.0662833)
p2 = (31.83,35.0708167)

NUM_TESTS = 100000
for strategy in vincenty, great_circle:
    before = datetime.datetime.now()
    for i in range(NUM_TESTS):
        d=strategy(p1, p2).meters
    after = datetime.datetime.now()
    duration = after-before
    print "%-40s: Total %s, (%s per calculation)" % (strategy, duration, duration/NUM_TESTS)

結論: Vincentyの式は大円に比べて計算時間が2倍であり、テストされたポイントでの精度向上は約0.17%です。

計算時間はごくわずかであるため、Vincentyの式はあらゆる実用的なニーズに適しています。

更新whubercffkおよびcffkの回答による洞察に富んだコメントに従って、精度の向上を測定ではなくエラーと比較することに同意します。したがって、Vincentyの式は数桁正確で、〜0.17%ではありません。


3
+1よくやった。地球全体のエラーの一般的な分析については、gis.stackexchange.com/questions/25494のスレッドを参照してください。
whuber

3
Vincentyは、大円公式よりも何倍も正確に楕円測地線距離を計算します。したがって、Vincentyの精度向上がわずか0.17%であると言うのは誤解を招く可能性があります。(倍精度演算は、スライドルールを使用するよりも0.1%正確であると言うのと同じです。)
cffk 14年

14

geopyを使用している場合、great_circleおよびvincentyの距離も同様に取得するのに便利です。この場合、より正確な結果が得られるもの、つまりビンセントを常に使用する必要があります。(指摘したように)2つの考慮事項は、速度と精度です。

Vincentyは2倍遅いです。しかし、おそらく実際のアプリケーションでは、実行時間の増加はごくわずかです。あなたのアプリケーションが100万の距離計算を要求したとしても、数秒の時間の違いについて話しているだけです。

使用するポイントの場合、vincentyの誤差は6μmであり、大円距離の誤差は0.75 mです。その場合、vincentyの精度は120000倍になります(0.17%の精度ではありません)。一般的なポイントの場合、大円距離の誤差は最大0.5%です。では、距離に0.5%の誤差がありますか?カジュアルに使用する場合(ケープタウンからカイロまでの距離は?)、おそらく可能です。ただし、多くのGISアプリケーションには、より厳しい精度要件があります。(0.5%は1kmで5mです。実際に違いがあります。)

ほぼすべての深刻なマッピング作業は参照楕円体で実行されるため、楕円体でも距離を測定する必要があります。たぶん、今日は大圏距離で逃げることができます。ただし、新しいアプリケーションごとに、これがまだ受け入れられるかどうかを確認する必要があります。ベターは、開始からの楕円距離を使用することです。夜はよく眠れます。

補遺(2017年5月)

@ craig-hicksの回答への返信。geopyのvincenty()メソッドには潜在的に致命的な欠陥があります:それはほぼ対pod点に対してエラーを投げます。コード内のドキュメントは、反復回数を増やすことを提案しています。しかし、vincenty()で使用される反復法はそのような点に対して不安定であるため、これは一般的な解決策ではありません(各反復は正しい解からさらに進んでいきます)。

問題を「潜在的に致命的な」とみなすのはなぜですか?別のソフトウェアライブラリ内で距離関数を使用する場合は、例外を処理できる必要があるためです。NaNまたは大圏距離を返すことでそれを処理することは満足のいくものではないかもしれません。なぜなら、得られる距離関数は、例えば、見晴らしの良い木での使用を妨げる三角形の不等式に従わないからです。

状況は完全に暗いわけではありません。私のpythonパッケージ geographiclibは、任意の障害が発生することなく、正確測地距離を計算します。geopyプルリクエスト#144は、それが利用可能かどうgeographiclibパッケージを使用するgeopyの距離関数を変更します。残念ながら、このプルリクエストは2016年8月からずっと制限されています。

補遺(2018年5月)

geopy 1.13.0は現在、距離の計算にgeographiclibパッケージを使用しています。次に、サンプルコールを示します(元の質問の例に基づく)。

>>> from geopy.distance import great_circle
>>> from geopy.distance import geodesic
>>> p1 = (31.8300167,35.0662833) # (lat, lon) - https://goo.gl/maps/TQwDd
>>> p2 = (31.8300000,35.0708167) # (lat, lon) - https://goo.gl/maps/lHrrg
>>> geodesic(p1, p2).meters
429.1676644986777
>>> great_circle(p1, p2).meters
428.28877358686776

3

ここに2番目の回答を掲載することをおaび申し上げますが、@ craig-hicksのリクエストに応答する機会を利用して、測地線距離を計算するためのさまざまなアルゴリズムの精度とタイミングの比較を提供します。これは私が私に作るコメント言い換えプルリクエスト#144 geopy内で使用する測地線のための私のアルゴリズムの2つの実装の1つの使用を可能にgeopyために、1は、 ネイティブのPython実装、測地線(geographiclib) 、およびその他の用途C実装、geodesic(pyproj)

タイミングデータは次のとおりです。時間はコールごとのマイクロ秒です

method                          dist    dest
geopy great_circle              20.4    17.1
geopy vincenty                  40.3    30.4
geopy geodesic(pyproj)          37.1    31.1
geopy geodesic(geographiclib)  302.9   124.1

これが私の測地線テストセットに基づく測地線計算の精度です 。誤差はミクロン単位(1e-6 m)で与えられます

method                        distance destination
geopy vincenty                 205.629  141.945
geopy geodesic(pyproj)           0.007    0.013
geopy geodesic(geographiclib)    0.011    0.010

宛先関数の悪いバグを修正するhannoscheのプルリクエスト#194を含めました。この修正がない場合、vincentyの宛先計算のエラーは8.98メートルです。

テストケースの19.2%がvincenty.distanceで失敗しました(反復= 20)。ただし、テストセットは、この障害が発生するケースに偏っています。

WGS84楕円体上のランダムな点により、Vincentyアルゴリズムは1000000回のうち16.6回失敗することが保証されています(正しい解決策はVincentyメソッドの不安定な固定点です)。

Vincentyのgeopy実装と繰り返し= 20の場合、失敗率は1000000あたり82.8です。繰り返し= 200の場合、失敗率は1000000あたり21.2です。

これらの割合は小さいものの、障害は非常に一般的です。たとえば、1000個のランダムポイントのデータセット(おそらく世界の空港を考えてみてください)では、完全な距離行列の計算は平均16回失敗します(反復= 20)。


2

geopy.distanceパッケージは、vincenty()をデフォルトとする関数 "distance()"を提供しているようです。将来的にvincenty()から逸脱する場合に備えて、原則としてdistance()をパッケージの推奨事項として使用することをお勧めします(そうでない場合)。読み続けて:

このドキュメントノートは、指定したvincenty()関数のソースコードに含まれています。

注:このVincenty距離の実装は、いくつかの有効なポイントに対して収束できません。場合によっては、反復回数を増やすことで結果を得ることができます(iterationsクラス__init__で指定されたキーワード引数、デフォルトは20)。:class:を使用することをお勧めします。.great_circleこれはわずかに精度が低くなりますが、常に結果を生成します。

上記のコメント/メモ付きのソースコードは、 https://github.com/geopy/geopy/blob/master/geopy/distance.py にあります。vincenty()の定義までスクロールします。

それでも、distance()の調整時にそのパッケージで使用されるデフォルトの距離関数はvincenty()関数です。これは、収束の失敗が壊滅的ではなく、妥当な答えが返されることを意味します。最も重要なのは例外が生成されないことです。

更新:「cffk」で述べたように、アルゴリズムが収束しない場合、vincenty()関数は明示的にValueError例外をスローします-関数の説明には記載されていません。したがって、ドキュメントにはバグがあります。


いいえ、vincenty()メソッド例外生成できます。多くの場合、ほぼ対points点間の距離の計算にのみ影響するため、これは重要ではないと主張されています。ただし、このような失敗は、三角形の不等式が失敗することを意味するため、Vincenty距離を使用して、有利な点ツリーを使用して最近傍検索を実装することはできません(たとえば、最も近い空港の位置を効率的に決定できます)。この問題を回避するには、距離にGeographicLibを使用するこのgeopy pull request github.com/geopy/geopy/pull/144を使用できます。
cffk

@cffk-あなたのコメントやリンクから確実に識別することはできませんが、「geopy pull request」はルックアップテーブルかもしれないと推測しています-それはありますか?ディスカッションは、ルックアップテーブルが利用できない(ダウンロードされる)場合と、利用できる場合の2つに分けることができます。
クレイグヒックス

@cffk-利用できない場合:まず、ドキュメントにはバグがあります。これは主に、計画された例外の説明が含まれていないためです(raise ValueError( "Vincenty formula failed to収束!"))。それは、ほぼ正反対のポイントの測定で生じる不安定性を説明していません。内部で例外をキャッチして代わりに大円の値を返すvincentyクラスにvincenty_noexcpt関数を追加し、デフォルト設定であるdistance = vincenty_noexcepにすることをお勧めします。
クレイグヒックス

@cffk-ルックアップテーブルが使用可能な場合:ルックアップメソッドは多くの場合キャッシュの外に出るため、時間がかかるため、多くのテストとタイミングをお勧めします。デフォルトとしてvincentyメソッドを「pull」メソッドに置き換えると、「pull」パッケージをpythonディレクトリにダウンロードする人は、vincentyへのすべての既存の呼び出しをpullの呼び出しに変更することを意味します。 「プル」メソッドを慎重かつ明示的に試してみたかった。
クレイグヒックス

@ craig-hicks-いいえ、「プルリクエスト」は距離を測定するためのより良いアルゴリズムに置き換えられます(doi.org/10.1007/s00190-012-0578-zを参照これはVincentyよりも正確で、常に結果を返します、ほぼ同じ時間がかかります。私はgeopyのメンテナではありません。このプルリクエストは昨年8月から休止しています。私が自分の娘を持っている場合、これはgeopyに置き換えられ(vincenty()はVincentyの代わりに新しいアルゴリズムを呼び出します)、それで説明は終わりです。
cffk

1

vincenty、haversine、またはcosinesの球面法則を使用するかどうかにかかわらず、使用する予定のコードの潜在的な問題、注意して緩和すること、vincenty vs haversine vs slocの問題に対処する方法に気づくのは賢明ですよく知られているかもしれないし、知られていないかもしれない、それぞれの潜んでいる問題/エッジケースに気付くと、異なるでしょう。熟練したプログラマーはこれを知っています。初心者はできません。フォーラムからのスニペットが特定の場合に予期しない何かをするとき、私はそれらのフラストレーションのいくつかを免れたいと思っています。これらのいずれかのバージョンを真剣に使用する場合、vincenty、haversine、sloc、SE、SO、Reddit、Quoraなどは、ソリューションの初期コーディングで限定的なヘルプを提供した可能性がありますが、それは意味しません彼らの解決策または受け入れられた「答え」には問題はありません。プロジェクトが十分に重要である場合、適切な妥当な量の研究に値します。マニュアルを読み、ドキュメントを読んで、そのコードのコードレビューが存在する場合はそれを読んでください。100回以上支持されたスニペットまたは要点をコピーして貼り付けても、その安全性が包括的で保証されているという意味ではありません。

cffkが投稿した興味深い答えは、例外やその他の問題を引き起こす可能性のある、パッケージ化されたソリューションに潜むエッジケースに気付くポイントを上げます。その投稿で行われた具体的な主張は、現在追求する私の時間予算を超えていますが、少なくとも1人のビンセンティの実装を含む特定のパッケージに潜んでいる問題があり、少なくとも1人が改善することを提案していますこれらの困難に遭遇するリスクを最小化または排除するために、何らかの方法で。私はvincentyに関するトピックにこれ以上追加しません(それについてはあまりにも無知すぎる)が、代わりにhaversineになります。少なくとも一部はOPに関するトピックです。

一般的に公開されているHaversine式は、Pythonでも他の言語でも、今日のほとんどすべてのIntelおよびIntelのようなシステム、およびARMプロセッサ、powerPCなどでIEEE 754浮動小数点仕様を使用する可能性が最も高いためです。また、浮動小数点近似と丸めのために、180度のアーク距離に近い、または180度のアーク距離で、まれではあるが実際の反復可能な例外エラーの影響を受けやすくなります。一部の初心者は、この状況にまだ噛まれていないかもしれません。このfp仕様は概算と丸めを行うため、fp64を呼び出すコードが例外エラーを引き起こす可能性があるという意味ではありません。しかし、いくつかのコード、IEEE 754 fp64の近似と丸めにより、そのような値を完全に評価すると予想される数学メソッドの領域から値がわずかに外れることがある、いくつかの式はそれほど明白なエッジケースを持たない場合があります。例... sqrt()。負の値がsqrt(-0.00000000000000000122739)などのsqrt()に到達すると、例外エラーが発生します。解決策に向かって進む方法であるHaversine式には、atan2()に2つのsqrt()メソッドがあります。のAを計算し、次いで、SQRTに使用される()、地球上の正反対の点で、わずかに非常にわずかに、0.0より下または1.0より上ためのfp64近似を逸脱することができ、丸め、まれに、しかし反復。このコンテキストでは、一貫性のある信頼性の高い再現性により、これは例外リスクであり、孤立したランダムなフリュークではなく、保護するためのエッジケースであり、軽減します。必要な保護なしのhaversineの短いpython3スニペットの例を次に示します。

import math as m

a = m.sin(dlat / 2)**2 + m.cos(lat1) * m.cos(lat2) * m.sin(dlon / 2)**2
c = 2 * m.atan2(m.sqrt(a), m.sqrt(1 - a))
distance = Radius * c

非常に近くまたは対pod点で、式の最初の行で計算され値は、負の値を逸脱する場合がありますが、めったにありませんが、同じ緯度座標で繰り返します。これらのまれな発生を保護/修正するには以下に示すように計算後に単純に追加できます。

import math as m

note = ''

a = m.sin(dlat / 2)**2 + m.cos(lat1) * m.cos(lat2) * m.sin(dlon / 2)**2
if a < 0.0: a = 0.0 ; note = '*'
if a > 1.0: a = 1.0 ; note = '**'
c = 2 * m.atan2(m.sqrt(a), m.sqrt(1 - a))
distance = Radius * c

# note = '*'  # a went below 0.0 and was normalized back to 0.0
# note = '**' # a went above 1.0 and was normalized back to max of 1.0

もちろん、ここでは関数全体を示していませんが、頻繁に投稿される短いスニペットです。ただし、これは、aをテストし必要に応じて正規化することで、sqrt()の保護を示します。note = '' up topは、関数の結果と共に返される場合、値が割り当てられる前にノートが使用されていることをバイトコードステージが抗議しないようにするためのものです。

この2つのaテストを追加するだけの簡単な変更により、sqrt()関数は満足になり、コードには呼び出しコードに返される追加のメモがあり、結果がわずかに正規化されたこととその理由を警告します。気にかける人もいれば、気にしない人もいますが、例外エラーを防ぐために、そうでなければ「発生する」ことがあります。try exceptブロックは例外をキャッチするかもしれませんが、そうするように明示的に書かれていない限り修正しません。それは直後に補正ライン(複数可)のコードに簡単に思える計算行。徹底的にスクラブされた入力は、ここでブロック以外のtryを必要としません。

要約、haversineを使用し、パッケージまたはライブラリを使用するのではなく明示的にコーディングする場合、選択する言語に関係なく、テストして、0.0 <= a <= 1.0の必要な範囲に戻るように正規化することをお勧めしますc計算で次の行を保護します。しかし、haversineコードスニペットの大部分はそれを示しておらず、リスクについては言及していません。

経験:世界中で徹底的なテスト中に、0.001度刻みで、CPU冷却の信頼性を付随的にテストする1か月の間に、例外、信頼性の高い一貫した反復可能な例外を引き起こした緯度経度の組み合わせでハードドライブをいっぱいにしましたファン、そして私の忍耐。はい、それらのログの目的は主にポイントを証明することだったので、私はそれ以来それらのログのほとんどを削除しました(しゃれが許可されている場合)。しかし、テスト用に保存された「問題の緯度経度値」の短いログがいくつかあります。

精度:ドメインとその小さなビットを正規化することで、aとHaversineの結果全体の精度がいくらか失われますか?大したことではないかもしれませんが、おそらくfp64の近似値と端数処理が既に導入されていたため、ドメインからのわずかなドリフトが発生していました。Haversineがvincentyを超えて受け入れられることがすでにわかっている場合、よりシンプルで、高速で、カスタマイズ、トラブルシューティング、および保守が容易な場合、haversineはプロジェクトに適したソリューションです。

私は地球上の位置から見た空のオブジェクト間の角距離を測定するために頭上に投影された天球でヘイバーシンを使用しました。投影された理論上のスカイスフィアは、地球の表面上の位置から2つのオブジェクト間の角度距離と視角を測定する場合、完全な球体です。それは私のニーズに完全に合っています。ですから、特定のアプリケーションでは(十分に私の目的の範囲内で)Haversineは非常に有用で非常に正確です...しかし、GISまたはナビゲーションのために地球上で、または天体の観測および測定でそれを使用する場合、対pod点または対anti点に非常に近い場合、テストにより必要に応じて、必要なドメインに戻します。

保護されていないHaversineはインターネット中にあり、JPLの誰かからのように、1985年以前、IEEE 754以前の浮動小数点仕様であったと思われる、いくつかの保護を示す古いusenetの投稿を見たことがあります。他の2つのページでは、対pod点の近くで起こりうる問題について言及しましたが、それらの問題、またはそれらを軽減する方法については説明しませんでした。したがって、信頼できるプロジェクトにコピーして貼り付けたコードをさらに調査し、エッジケースをテストするのに十分なプラクティスを常に理解していない初心者(私のような)に懸念があります。cffkの興味をそそる投稿は、これらのタイプの問題で公開されており、頻繁に言及されておらず、スニペットで保護するために公開されていることはめったになく、投稿された保護されていない議論されていないバージョンの量と比較して、この方法で議論されることはめったになかったという点で更新されました。

20190923の時点で、haversineフォーミュラのWikiページには、コンピューティングデバイスの浮動小数点の問題により、対pod点で起こりうる問題が実際に言及されています...

https://en.wikipedia.org/wiki/Haversine_formula

(現時点では、wikiページには直接リンクするセクションのhtmlアンカーがないため、ページが読み込まれた後、そのブラウザーページで「これらの数式を使用するとき」を検索すると、言及された対with点に関するヘイバーシンの問題を、より公式に参照してください。)

そして、この他のサイトにも非常に短い言及があります:

https://www.movable-type.co.uk/scripts/latlong.html

「丸めエラーに対する保護を含む」ためにそのページで検索を行うと、これがあります...

atan2が利用できない場合、cは2⋅asin(min(1、√a))から計算できます(丸め誤差に対する保護を含む)。

まれに、丸めエラーが記載されているケースがあり、asin()バージョンでは保護が表示されますが、atan2()バージョンでは表示または表示されません。ただし、少なくとも丸め誤差のリスクについては言及されています。

Haversineを使用する24/7/365アプリケーションであるimhoは、重要かつシンプルなディテールとして、対anti点付近のこの保護を必要とします。

どのHaversineパッケージがこの保護を行うか含まないかはわかりませんが、これにまったく慣れておらず、よく公開されている「スニペット」バージョンを使用する場合は、保護が必要であることがわかります。その保護は実装が非常に簡単です。つまり、vincentyを使用しておらず、パッケージのコードを変更するための簡単なアクセスなしにパッケージ化されたHaversineを使用していない場合です。

IOWは、vincenty、haversine、slocのいずれを使用する場合でも、コードの問題、注意し、緩和すること、およびvincenty vs haversine vs slocの問題に対処する方法が、それぞれの問題に気付くにつれて異なることを認識する必要があります一般的に知られているかもしれないし、知られていないかもしれない問題/エッジケースを潜んでいます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.