Різниця між розрахунками Вінсенті та величиною відстані великого кола?


16

Пакет геопітів Python містить дві методики вимірювання відстані: формули Великого кола та формули Вінсента .

>>> 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

Згідно з Вікіпедією, формула Вінсенті повільніша, але точніша :

Формули Вінсенті - це два споріднені ітераційні методи, що використовуються в геодезії для обчислення відстані між двома точками на поверхні сфероїда, розроблені Тадеєм Вінсенті (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)

На закінчення: формула Вінсенті подвоює час обчислення порівняно з великим колом, а коефіцієнт підсилення його точності у випробуваній точці становить ~ 0,17%.

Оскільки час обчислення незначний, формула Вінсенті є кращою для кожної практичної потреби.

Оновлення : Після проникливих коментарів відповіді whuber and cffk та cffk я погоджуюся, що підвищення точності слід порівнювати з помилкою, а не з вимірюванням. Отже, формула Вінсенті на кілька порядків точніша, а не ~ 0,17%.


3
+1 Молодці. Щоб отримати загальний аналіз помилок у всьому світі, перегляньте посилання на gis.stackexchange.com/questions/25494 .
whuber

3
Вінсент обчислює еліпсоїдальні геодезичні відстані в багато разів точніше, ніж формула великого кола. Так що твердження про те, що коефіцієнт підвищення точності Вінсенті становить лише 0,17%, вводить в оману. (Це рівнозначно тому, що арифметика подвійної точності на 0,1% точніша, ніж використання правила слайда.)
cffk

14

Якщо ви використовуєте геопію, то відстані great_circle та vincenty однаково зручні для отримання. У цьому випадку ви майже завжди повинні використовувати той, який дає більш точний результат, тобто винності. Дві міркування (як ви зазначаєте) - це швидкість і точність.

Вінсент у два рази повільніше. Але, ймовірно, у реальному застосуванні збільшений час роботи є незначним. Навіть якщо ваша заявка вимагала розрахунку мільйона відстаней, ми говоримо лише про різницю у пару секунд.

Для точок, які ви використовуєте, похибка в Вінсенсі становить 6 мкм, а похибка на великій відстані кола - 0,75 м. Тоді я б сказав, що вінсент у 120000 разів точніший (а не на 0,17% точніший). Для загальних точок похибка великої відстані кола може становити до 0,5%. Тож чи можна жити з 0,5% помилкою на відстані? Для випадкового використання (яка відстань від Кейптауна до Каїра?), Напевно, ви можете. Однак у багатьох додатках ГІС є більш суворі вимоги до точності. (0,5% - це 5 м за 1 км. Це дійсно має значення.)

Майже всі серйозні роботи з картографуванням проводяться на еталонному еліпсоїді, і тому є сенс, що відстані слід вимірювати і на еліпсоїді. Можливо, сьогодні ви можете піти з дистанції великих кіл. Але для кожної нової програми вам доведеться перевірити, чи це все-таки прийнятно. Краще просто використовувати еліпсоїдальну відстань від початку. Ви краще будете спати вночі.

ДОДАТКУ (травень 2017)

У відповідь на відповідь, яку дав @ craig-hicks. Метод vincenty () в геопії має потенційно фатальний недолік: він видає помилку майже для антиподальних точок. Документація в коді дозволяє збільшити кількість повторень. Але це не загальне рішення, оскільки ітераційний метод, що використовується vincenty (), нестійкий для таких точок (кожна ітерація відводить вас далі від правильного рішення).

Чому я характеризую проблему як "потенційно смертельну"? Оскільки будь-яке використання функції відстані в іншій бібліотеці програмного забезпечення повинно мати можливість обробляти виняток. Поводження з ним шляхом повернення NaN або відстані великого кола може бути незадовільним, оскільки отримана функція відстані не буде підкорятися нерівності трикутника, що перешкоджає його використанню, наприклад, у деревах, що перебувають у видобувних точках.

Ситуація не зовсім похмура. Мій пакет python geographiclib точно обчислює геодезичну відстань без жодних збоїв. Запит geopy тягнути # 144 змінює відстань функцію geopy, щоб пакет використання geographiclib , якщо він доступний. На жаль, цей запит на притягнення знаходиться з кінцівкою з серпня 2016 року.

ДОДАТКУ (травень 2018)

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

Мої вибачення за розміщення другої відповіді тут, але я скориставшись можливістю відповісти на запит від @ craig-hicks, щоб забезпечити точність та часові порівняння різних алгоритмів обчислення геодезичної відстані. Це перефразовує коментар, який я вказую на свій запит № 144 про геопію, який дозволяє використовувати одну з двох реалізацій мого алгоритму для геодезики, яка використовується в геопії, одна - це вбудована пітонна реалізація, геодезична (географічна ліб ) , а інша використовує реалізація в C, геодезичний (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

Ось точність геодезичних розрахунків на основі мого геодезичного тестового набору . Похибки наведені в одиницях мікронів (1е-6 м)

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

Я включив запит на тягнення # 194 на hannosche, який виправляє погану помилку у функції призначення. Без цього виправлення похибка в розрахунку місця призначення для вінсентів становить 8,98 метрів.

У 19,2% випадків тестування не вдалося з vincenty.distance (ітерації = 20). Однак тестовий набір спрямований на випадки, які спричинили б цей збій.

З випадковими точками на еліпсоїді WGS84 алгоритм Вінсенті гарантується невдачею 16,6 з 1000000 разів (правильне рішення - це нестабільна фіксована точка методу Вінсенті).

З геопічною реалізацією Вінсенті та ітерацій = 20 коефіцієнт відмов становить 82,8 на 1000000. При ітераціях = 200 коефіцієнт відмов становить 21,2 на 1000000.

Незважаючи на те, що ці показники невеликі, збої можуть бути досить поширеними. Наприклад, у наборі даних з 1000 випадкових точок (можливо, думаю, аеропорти у світі), обчислення матриці на повну відстань буде в середньому 16 разів (з ітераціями = 20).


2

Здається, що пакет geopy.distance пропонує функцію "distance ()", яка за замовчуванням відповідає vincenty (). Я б рекомендував використовувати відстань (), в принципі, так як це рекомендація щодо пакету, якщо у майбутньому колись буде відхилено від vincenty () (навряд чи так). Продовжити читання →:

Ця документаційна примітка включена у вихідний код для вказаної вами функції vincenty ():

Примітка. Ця реалізація відстані Вінсенті не збігається для деяких дійсних точок. У деяких випадках результат можна отримати, збільшивши кількість ітерацій ( iterationsаргумент ключового слова, наведений у класі __init__, за замовчуванням 20). Можливо, бажано використовувати: class:, .great_circleякий є гранично менш точним, але завжди дає результат.

Вихідний код із цим вище коментарем / приміткою можна знайти за посиланням https://github.com/geopy/geopy/blob/master/geopy/distance.py Прокрутіть униз до визначення vincenty ()

Тим не менш, функція відстані за замовчуванням, яка використовується цим пакетом при калібруванні відстані (), - це функція vincenty (), що означає, що невдача конвергенції не є катастрофічною, а обґрунтована відповідь повертається - головне, щоб виняток не створювався.

Оновлення: Як зазначає "cffk", функція vincenty () явно викидає виняток ValueError, коли алгоритм не конвергується - хоча це не зафіксовано в описі функції. Отже, документація є помилковою.


Ні, метод vincenty () може створити виняток. Часто стверджують, що це не має значення, оскільки це впливає лише на розрахунок відстаней між майже антиподальними точками. Однак такі збої означають, що нерівність трикутника виходить з ладу, і тому відстань Вінсенті не може бути використана для здійснення пошуку найближчого сусіда за допомогою дерева точки перегляду (що дозволило б, наприклад, ефективно визначити місце розташування найближчого аеропорту). Щоб вирішити цю проблему, ви можете скористатися цим запитом на геопічне тягання github.com/geopy/geopy/pull/144, який використовує GeographicLib для відстаней.
cffk

@cffk - Я не можу з упевненістю розрізнити ваш коментар чи посилання, але я здогадуюсь, що "запит на геопічне витягнення" може бути таблицею пошуку - чи не так? Обговорення можна розділити на два: випадок, коли таблиця пошуку недоступна (завантажена) та випадок, коли вона доступна.
Крейг Хікс

@cffk - У випадку, коли вона недоступна: По-перше, документація є помилковою насамперед тому, що вона не включає опис запланованого винятку (підвищити ValueError ("формула Вінсенті не вдалося зблизитись!")), а й тому, що це не описує нестабільність як виникаючу при вимірюванні точок, майже антиподальних. Я рекомендую додати функцію vincenty_noexcpt до класу Vincenty, який внутрішньо перехоплює виняток і замість цього повертає велике значення кола, роблячи це налаштуванням за замовчуванням: distance = vincenty_noexcep.
Крейг Хікс

@cffk - У випадку, коли доступна таблиця пошуку: я б порадив багато тестування та термінів, оскільки методи пошуку часто виходять за межі кеш-пам'яті, і тому вони дорогі. Заміна методу vincenty методом "pull", оскільки за замовчуванням може означати, що хтось, хто завантажує пакет "pull" в каталог python, змінить усі існуючі виклики vincenty на виклики для виклику - це може бути проблематично, якщо користувачі (і) дійсно просто хотів обережно і чітко спробувати метод «тягнути».
Крейг Хікс

@ craig-hicks - Ні, запит "тягнути" замінює кращий алгоритм (на мене!) для вимірювання відстаней, див. doi.org/10.1007/s00190-012-0578-z Це точніше, ніж Вінсент, завжди повертає результат , і займає приблизно той самий час. Я не є обслуговувачем геопії, і цей запит на притягнення не працює з минулого серпня. Якби я мав свої барабани, це було б замінене на геопію (і вінсенті () називав би новий алгоритм замість Вінсенті), і це було б закінченням дискусії.
cffk

1

Незалежно від того, чи використовуєте Вінсенті, або Гаверсин, або сферичний закон косинусів, є розумність усвідомити будь-які потенційні проблеми з кодом, який ви плануєте використовувати, речі, на які слід стежити і пом'якшувати, і як можна вирішувати проблеми з Вінсенті проти Хаверсіна проти слонів. буде відрізнятись, коли стане відомо про якісь запізнілі проблеми / крайові випадки, які можуть бути, а можуть і не бути широко відомими. Це знає досвідчений програміст. Новачки не можуть. Я сподіваюся пошкодити деякі з них розчарування, коли фрагмент з форуму робить щось несподіване в певних випадках. Якщо хтось серйозно збирається використовувати якусь версію будь-якого з них, vincenty, haversine, sloc, то SE, SO, Reddit, Quora тощо може бути надано обмежену допомогу в якомусь початковому кодуванні рішення, але це не означає, що їх рішення або прийнята «відповідь» не містить питань. Якщо проект є досить важливим, він заслуговує на відповідний розумний обсяг досліджень. Прочитайте посібник, прочитайте документи, і якщо огляд цього коду існує, прочитайте це. Копіювання та вставлення фрагмента або сутінки, яке було анонсовано сто і більше разів, не означає, що його безпека є всебічною та забезпеченою.

Інтригуюча відповідь, опублікована cffk, породжує сенс усвідомлення ховаються крайових випадків у пакетних рішеннях, які можуть спричинити винятки чи інші труднощі . Конкретні претензії, висловлені на цій посаді, перевищують мій бюджет часу, який я повинен переслідувати в даний час, але я зазначаю, що в певних пакетах дійсно існують проблеми, в тому числі принаймні одна реалізація, яка стосується хоча б однієї особи, яка запропонувала поліпшити. так чи інакше, щоб мінімізувати або усунути ризик виникнення цих труднощів. Я не буду більше додавати до цієї теми, що стосується Вінсенті (будучи її занадто неосвіченою), але перейду натомість до хаверсину, принаймні частково на тему з ОП.

Популярна в опублікованій формулі haversine, будь то python чи іншою мовою, тому що найімовірніше буде використовувати специфікацію IEEE 754 з плаваючою точкою для більшості всіх систем Intel та Intel, схожих сьогодні, та процесорів ARM, powerPC тощо. також можуть бути сприйнятливими до рідкісних, але реальних і повторюваних помилок винятків на близькій відстані або на відстані 180 градусних дуг, антиподальних точках через наближення плаваючої точки та округлення. Деякі новачки, можливо, ще не покусані цією ситуацією. Оскільки ця специфікація fp наближається і округляє, це не означає, що будь-який код, який викликає fp64, може викликати помилки винятку, ні. Але якийсь код, деякі формули можуть мати не настільки очевидні крайові випадки, коли наближення та округлення IEEE 754 fp64 можуть призвести до того, що значення дещо відхилиться від області математичного методу, який, як очікується, бездоганно оцінить таке значення. Приклад ... sqrt (). Якщо негативне значення знайде шлях до sqrt (), наприклад sqrt (-0.00000000000000000122739), виникла помилка виключення. У формулі Гаверсина, способі просування до рішення, є два методи sqrt () в atan2 (). Thea, що обчислюється і потім використовується в sqrt (), може в антиподальних точках на земній кулі трохи збиватися нижче 0,0 або вище 1,0, дуже незначно через наближення fp64 та округлення, рідко, але повторно. Послідовна надійна повторюваність у цьому контексті робить цей ризик винятком, кращим захистом для пом'якшення, а не ізольованим випадковим випадком. Ось приклад короткого фрагмента 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

Дуже поруч або в діаметрально протилежних точок, розраховується в першому рядку формули можуть відхилитися негативні, рідко, але повторюваністю з тими ж координатами широти Lon. Для захисту / виправити ті рідкісні випадки, можна просто додати, після в розрахунок, як показано нижче:

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

Звичайно, я тут не показав всю функцію, але короткий фрагмент, як це часто розміщується. Але це показує захист sqrt (), випробувавши a , та нормалізувавши його при необхідності, також заощаджуючи необхідність поставити всю справу за винятком спробу. Примітка = '' вгорі - це запобігти протестуванню етапу байт-коду, щоб нотатка була використана перед призначенням значення, якщо вона повертається з результатом функції.

З допомогою цього простого зміни, додавання двох тестів, SQRT () функції будуть щасливі, і код тепер має додаткову ноту , яка може бути повернута в викликає код, щоб попередити про те , що результат був трохи нормалізувалися, і чому. Деяким може бути байдуже, іншим - ні, але його немає, запобігаючи помилці винятку, що "може" статися інакше Спроба, крім блоку, може зафіксувати виняток, але не виправити його, якщо прямо не написано для цього. Здається , простіше код корекції лінії (и) відразу після розрахунку лінії. Ретельно прочищений вхід не повинен взагалі вимагати спроб, крім блоку.

Резюме, при використанні гаверсінуса, кодуються в явному вигляді , а не НЕ з допомогою пакета або бібліотеки, незалежно від того , ваш мова за вибором, було б гарною ідеєю для перевірки і нормалізації в задню частину в потребу діапазоні 0,0 <= а <= 1,0 в порядку для захисту наступного рядка своїми розрахунками c . Але більшість фрагментів коду Гаверсину не показують його та не згадують про ризик.

Досвід: під час ретельного тестування по всьому світу, з кроком 0,001 градуса, я заповнив жорсткий диск із комбінаціями lat lon, які спричинили виняток, надійний послідовний повторюваний виняток, протягом місяця також побічно тестуючи надійність охолодження процесора вентилятор, і моє терпіння. Так, я з тих пір видалив більшість цих журналів, оскільки їх метою було переважно довести точку (якщо каламбур дозволений). Але у мене є декілька коротших журналів «проблемних значень lat lon», які зберігаються для тестування.

Точність: Чи втратить а та весь хаверсиновий результат певну точність, нормалізуючи його, що повернеться до домену? Не так багато, можливо, не більше, ніж наближення та округлення fp64 вже вводили, що спричинило незначне відхилення від домену. Якщо ви вже знайшли гаверсин, прийнятний у порівнянні з вінсенсі - простіший, швидший, простіший у налаштуванні, усунення несправностей та обслуговування, тоді гаверсин може стати хорошим рішенням для вашого проекту.

Я використовував гаверсин на наземній проектованій небосхилі для вимірювання кутових відстаней між об'єктами на небі, як видно з положення на землі, картографування по азимуту та альт для скісфери lat lon, еквівалентних координат, ніяких еліпсоїдів взагалі не враховувати, оскільки Прогнозована теоретична скеля є ідеальною сферою, коли мова йде про вимірювання кутових відстаней погляду кутів між двома об'єктами від положення на земній поверхні. Він ідеально відповідає моїм потребам. Так, хаверин все ще є дуже корисним і дуже точним у певних програмах (і в рамках моїх цілей) ... але якщо ви все-таки використовуєте його, чи то на Землі для ГІС, чи навігації, чи в спостереженнях та вимірах об'єктів неба, захищайте це у випадку антиподальних точок або дуже поблизу антиподальних точок, шляхом тестування aі при необхідності повернути його до потрібного домену.

Незахищений хаверин є по всьому Інтернету, і я бачив лише один старий пост Usenet, який показав певний захист, я думаю, хтось із JPL, і це, можливо, було до 1985 року, специфікація з плаваючою точкою IEEE 754. На двох інших сторінках згадувались можливі проблеми поблизу антиподальних точок, але вони не описували ці проблеми, або як можна їх пом'якшити. Таким чином, існує стурбованість новичками (як я), які не завжди можуть добре зрозуміти належну практику для подальшого дослідження та перевірки крайових випадків, який-небудь код вони скопіювали та вставили у проект довіри. Інтригуюча публікація cffk була освіжаючою тим, що вона публічно використовує такі типи питань, які не часто згадуються, рідко публічно кодуються для захисту у фрагментах, і рідко обговорюються таким чином, порівняно з кількістю незахищених та не обговорюваних версій, які розміщуються.

Станом на 20190923 рік на вікі-сторінці формули haversine дійсно згадується проблема, яка можлива в антиподальних точках, через проблеми з плаваючою комою в обчислювальних пристроях ... заохочуючи ...

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

(тому що на цій сторінці wiki наразі немає HTML-прив’язки до розділу, до якого я б безпосередньо посилався, тому після завантаження сторінки зробіть пошук на цій сторінці браузера для "При використанні цих формул", і ви див. проблему Гаверсина щодо згаданих антиподальних точок (офіційно).

І цей інший сайт також дуже коротко згадує про нього:

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

Якщо ви знайдете на цій сторінці "включення захисту від помилок округлення", це таке ...

Якщо atan2 недоступний, c може бути обчислений з 2 ⋅ asin (min (1, √a)) (включаючи захист від помилок округлення).

Зараз є рідкісний приклад, коли згадуються помилки округлення та захист, показаний для версії asin (), але ще не згаданий або показаний для версії atan2 (). Але принаймні згадується ризик помилок округлення.

imho, будь-яка програма 24/7/365, яка використовує хаверсин, потребує такого захисту поблизу протиподіальних точок як важливої ​​та простої деталі.

Я не знаю, які пакети haversine роблять або не включають цей захист, але якщо ви все це новачок, і ви збираєтесь використовувати широко опубліковані "фрагменти" версії, тепер ви знаєте, що це потребує захисту, і цей захист дуже простий у здійсненні, тобто якщо ви не використовуєте vincenty і не використовуєте упакований гаверсин без легкого доступу для зміни коду пакету.

IOW, незалежно від використання vincenty чи haversine чи sloc, слід усвідомити будь-які проблеми з кодом, речі, на які слід спостерігати та пом'якшувати, і як можна вирішувати питання vincenty vs haversine vs sloc, коли вони стануть відомими для кожного ховаються проблеми / крайові випадки, які можуть бути або не бути широко відомими.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.