Обчислення середніх координат широти та довготи


19

Як я можу обчислити середнє значення між кількома плямами широти та довготи?

Чи варто просто обчислити середнє арифметичне як для лата, так і для lng?


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

1
Як були зібрані ці бали? Замість того, щоб запитувати, як уселити координати, можливо, запитайте, чи усереднення є відповідним способом компенсації помилок вимірювань. У цій книзі багато визначень помилок.
Кірк Куйкендалл

Лише зауважте, що є деякі крайові випадки, коли «середня точка» недостатньо чітко визначена: наприклад, де-небудь уздовж екватора можна було б бути «середнім» полюсів Н. та С.
Дан С.

Відповіді:


15

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

Метод, який я використовував для цього типу речей, полягає в перетворенні координат довготи / широти в 3d декартові координати (x, y, z). Порівняйте їх (для отримання декартового вектора), а потім знову конвертуйте. Зауважте, що вам, мабуть, не потрібно нормалізувати вектор, тому фактичний середній процес може бути простою сумою.


Редагувати, ось мій код:

Наступні перетворюють декартові координати у широту / довготу (у градусах): Видаліть RAD2DEGконстанти радіанів.

Latitude = MPUtility.RAD2DEG * Math.Atan2(z, Math.Sqrt(x * x + y * y));
Longitude = MPUtility.RAD2DEG * Math.Atan2(-y, x);

І тут ми обчислюємо декартові координати з широти / довготи (вказані в радіанах):

private void CalcCartesianCoord()
{
    _x = Math.Sin(LatitudeRadians) * Math.Cos(LongitudeRadians);
    _y = Math.Sin(LatitudeRadians) * Math.Sin(LongitudeRadians);
    _z = Math.Cos(LatitudeRadians); 
}

Обидва вирізані та вставлені з реального коду, отже, суміш градусів та радіанів. Тут є властивості, які виконують деякі перетворення (наприклад LatitudeRadians, це властивість, яка повертає радіанне значення).

Зауважте, що можлива оптимізація: наприклад, дублювання синусових обчислень. Також обчислення тригерів може бути кешованим, якщо ви їх називаєте багато.


1
чудовий момент. Я не можу повірити, що забув згадати про це. Середнє значення біля стовпів та ліній дати покусало мене раніше.
Гленн

3
(+1) Проблема не обмежується полюсами та меридіаном + -180 градусів: коли широти точок, які слід усереднювати, значно змінюються, пряме усереднення координат lat / lon рівнозначне використанню проекції Пларі Каррі, яка вводить змінне метричне спотворення, що збільшується з широтою. Числових проблем немає, але середнє значення просто в неправильному місці. З цієї причини лат. Обчислення, запропоновані у відповіді @ Глена, рідко прийнятні, за винятком відносно невеликих неполярних областей.
whuber

@winwaed спасибі, чи можете ви запропонувати якийсь фрагмент коду (Java) чи хороший підручник для цього?
аневризм

1
Математику можна знайти на en.wikipedia.org/wiki/Spherical_coordinate у розділі "Декартові координати". (Моя реалізація C # та частково оптимізована - плюс я це
набираю

1
Я думаю, що у точних випадках використання техніки ви дуже правильні. Однак, якщо не потрібна гранична точність, усереднення WGS84 lat, координати lng у містах та навіть регіональних районах спрацьовують досить добре і дають результати, які є достовірно точними для більшості випадків використання середнього рівня.
Гленн

3

Параметри кластеризації : Я думаю, що концептуальне слово, яке охоплює цей тип операцій, є "кластеризацією". Усереднення на сьогоднішній день є найпростішим у здійсненні і добре працює для більшості цілей. Єдиний раз, коли б я скористався чимось іншим, це якщо ти турбуєшся про людей, що вийшли з ладу [Правка] ->, або жердинами або міжнародними дателінами. [Редагувати] -> також усереднення, хоча це дасть вам щось, що виглядає близько до центру кластеру, буде трохи відхилено через неточності проекції, спричинені тим, що градуси lat lng не завжди однакові відстані крім км / миль. Чим більша площа, середня середня величина, тим більше спотворення.

Ось порівняння кількох варіантів кластеризації

Середня (проста, найшвидша, неточна): просто підсумовуйте значення lat і діліть на кількість і зробіть те ж саме для значень lng. Обов’язково слідкуйте за переповненням, якщо ви використовуєте Int32, деякі системи (зокрема c #) мовчки переповнюватимуться до низьких чисел. Ви можете уникнути цих помилок, використовуючи точність з плаваючою комою для свого акумулятора. Однією з проблем цього методу є те, що люди, які пережили люди, можуть перекосити ваше місцезнаходження. [Редагувати] -> Інша справа, що математика біля полюсів та міжнародної лінійки дат не відповідає середньому рівню, а місця розташування погано перекручені.

Найближчий сусід (трохи важче, повільніше, не зовнішній вигляд) Замість того, щоб усереднюватись, можна було йти з фактичним місцем розташування з найменшою середньою відстані до всіх сусідів. Це щось на зразок прийняття «медіани». Суть полягає в тому, що це обчислювально дорого, оскільки ви порівнюєте кожну точку з кожною іншою точкою і обчислюєте відстань між ними. Наприклад, для кластеризації 10000 точок знадобиться 100 мільйонів обчислень відстані. Це не так повільно, але це, безумовно, не добре.

Grid Cell (потрібно трохи додатково налаштувати, набагато швидше, не упереджено) Це схоже на найближчого сусіда, але набагато швидше. Ви можете вибрати довільний рівень точності, скажімо, .01 deg lat lng (який приблизно в 1 км на населених широтах) і згрупувати свої бали у відрі .01 x .01 градуса. Тоді ви можете вибрати відро з найбільшою кількістю очок і взяти середнє значення серед цих балів або провести аналіз найближчого сусіда лише за цими балами. Я багато використовую цей метод із дійсно великими наборами даних (сотні мільярдів записів) і вважаю, що це хороший баланс між точністю та швидкістю.

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


@winwaed має велике значення щодо усереднення координат біля полюсів, і я також додав би міжнародну лінію дати. Наприклад, якщо у вас є одна точка на одній стороні і одна на іншій, ви отримуєте погані середні значення (а також обмежувальні поля). Це рідко з'являється, але коли це робиться, це справжня біль налагодження
Гленн

@whuber робить хорошу думку щодо дрейфуючих центрів при середньому рівні. Незважаючи на те, що усереднення дасть вам щось, що виглядає близько до центру кластеру, буде трохи відхилено через неточності проекції, викликані тим, що градусні відстані не завжди однакові відстані в км / милі. Чим більша площа в середньому, тим більше спотворення.
Гленн

0

Не впевнений у тому, що ви намагаєтесь досягти, але точка, широта якої є середньою широтою вихідного набору точок, а довгота - це середня довжина початкового набору точок, буде середньою точкою вихідного набору точок. [ОНОВЛЕННЯ]: У наведеному вище середній арифметичний середній.


У вашій відповіді avg = середнє арифметичне?
аневризм

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