Я думаю, что следующее может быть полезным приближением, которое масштабируется линейно, а не квадратично с количеством точек, и его довольно легко реализовать:
- вычислить центр масс M точек
- найти точку P0, максимально удаленную от M
- найти точку P1, максимально удаленную от P0
- аппроксимировать максимальный диаметр расстоянием между P0 и P1
Это можно обобщить, повторив шаг 3 N раз и взяв расстояние между PN-1 и PN
Шаг 1 можно эффективно выполнить, аппроксимируя M как среднее значение долготы и широты, что нормально, когда расстояния «небольшие» и полюса достаточно далеко. Другие шаги можно было бы выполнить, используя формулу точного расстояния, но они намного быстрее, если координаты точек можно аппроксимировать лежащими на плоскости. Как только «удаленная пара» (надеюсь, пара с максимальным расстоянием) найдена, расстояние до нее можно пересчитать по точной формуле.
Примером аппроксимации может быть следующее: если φ(M) и λ(M) — широта и долгота центра масс, вычисляемые как Σφ(P)/n и Σλ(P)/n,
- x(P) = (λ(P) - λ(M) + C) cos(φ(P))
- y(P) = φ(P) - φ(M) [это только для ясности, также может быть просто y(P) = φ(P)]
где C обычно равно 0, но может быть ± 360 °, если набор точек пересекает линию λ = ± 180 °. Чтобы найти максимальное расстояние, вам просто нужно найти
- max((x(PN) - x(PN-1))2 + (y(PN sub>) - y(PN-1))2)
(вам не нужен квадратный корень, потому что он монотонный)
То же самое преобразование координат можно использовать для повторения шага 1 (в новой системе координат), чтобы иметь лучшую начальную точку. Подозреваю, что при выполнении некоторых условий вышеописанные шаги (без повторения шага 3) всегда приводят к "истинной дальней паре" (моя терминология). Если бы я только знал, какие условия...
ИЗМЕНИТЬ:
Я ненавижу опираться на чужие решения, но кому-то придется.
По-прежнему сохраняя вышеуказанные 4 шага с необязательным (но, вероятно, полезным, в зависимости от типичного распределения баллов) повторением шага 3 и следуя решение Spacedman, выполнение вычислений в 3D преодолевает ограничения близости и расстояния от полюсов:
- х (Р) = грех (ф (Р))
- y(P) = cos(φ(P)) sin(λ(P))
- z(P) = cos(φ(P)) cos(λ(P))
(единственное приближение состоит в том, что это верно только для идеальной сферы)
Центр масс определяется выражением x(M) = Σx(P)/n и т. д., а максимальное значение, которое нужно искать, равно
- max((x(PN) - x(PN-1))2 + (y(PN sub>) - y(PN-1))2 + (z(PN) - z(PN- 1))2)
Итак: вы сначала преобразуете сферические координаты в декартовы, затем начинаете с центра масс, чтобы найти, по крайней мере, за два шага (шаги 2 и 3) самую удаленную точку от предыдущей точки. Вы можете повторять шаг 3 до тех пор, пока расстояние увеличивается, возможно, с максимальным количеством повторений, но это не уведет вас от локального максимума. Старт из центра масс тоже не очень поможет, если точки разбросаны по всей Земле.
РЕДАКТИРОВАТЬ 2:
Я достаточно выучил R, чтобы написать ядро алгоритма (хороший язык для анализа данных!)
Для плоского приближения без учета задачи вокруг линии λ=±180°:
# input: lng, lat (vectors)
rad = pi / 180;
x = (lng - mean(lng)) * cos(lat * rad)
y = (lat - mean(lat))
i = which.max((x - mean(x))^2 + (y )^2)
j = which.max((x - x[i] )^2 + (y - y[i])^2)
# output: i, j (indices)
На моем ПК поиск индексов i
и j
для 1000000 точек занимает меньше секунды.
Следующая 3D-версия немного медленнее, но работает для любого распределения точек (и не нуждается в поправках, когда λ =±180° линия пересекается):
# input: lng, lat
rad = pi / 180
x = sin(lat * rad)
f = cos(lat * rad)
y = sin(lng * rad) * f
z = cos(lng * rad) * f
i = which.max((x - mean(x))^2 + (y - mean(y))^2 + (z - mean(z))^2)
j = which.max((x - x[i] )^2 + (y - y[i] )^2 + (z - z[i] )^2)
k = which.max((x - x[j] )^2 + (y - y[j] )^2 + (z - z[j] )^2) # optional
# output: j, k (or i, j)
Вычисление k
может быть опущено (т. е. результат может быть получен с помощью i
и j
) в зависимости от данных и требований. С другой стороны, мои эксперименты показали, что дальнейший расчет индекса бесполезен.
Следует помнить, что в любом случае расстояние между полученными точками является оценкой, являющейся нижней границей "диаметра" множества, хотя очень часто это будет и сам диаметр (как часто зависит от данных.)
ИЗМЕНИТЬ 3:
К сожалению, относительная погрешность плоскостной аппроксимации в крайних случаях может достигать 1-1/√3 ≅ 42,3%, что может быть неприемлемым, хотя и очень редким. Алгоритм можно модифицировать, чтобы иметь верхнюю границу примерно 20%, которую я получил с помощью циркуля и линейки (аналитическое решение громоздко). Модифицированный алгоритм находит пару точек с локально максимальным расстоянием, затем повторяет те же шаги, но на этот раз начиная с середины первой пары, возможно, находя другую пару:
# input: lng, lat
rad = pi / 180
x = (lng - mean(lng)) * cos(lat * rad)
y = (lat - mean(lat))
i.n_1 = 1 # n_1: n-1
x.n_1 = mean(x)
y.n_1 = 0 # = mean(y)
s.n_1 = 0 # s: square of distance
repeat {
s = (x - x.n_1)^2 + (y - y.n_1)^2
i.n = which.max(s)
x.n = x[i.n]
y.n = y[i.n]
s.n = s[i.n]
if (s.n <= s.n_1) break
i.n_1 = i.n
x.n_1 = x.n
y.n_1 = y.n
s.n_1 = s.n
}
i.m_1 = 1
x.m_1 = (x.n + x.n_1) / 2
y.m_1 = (y.n + y.n_1) / 2
s.m_1 = 0
m_ok = TRUE
repeat {
s = (x - x.m_1)^2 + (y - y.m_1)^2
i.m = which.max(s)
if (i.m == i.n || i.m == i.n_1) { m_ok = FALSE; break }
x.m = x[i.m]
y.m = y[i.m]
s.m = s[i.m]
if (s.m <= s.m_1) break
i.m_1 = i.m
x.m_1 = x.m
y.m_1 = y.m
s.m_1 = s.m
}
if (m_ok && s.m > s.n) {
i = i.m
j = i.m_1
} else {
i = i.n
j = i.n_1
}
# output: i, j
Алгоритм 3D можно изменить аналогичным образом. Можно (как в 2D, так и в 3D случае) начать еще раз с середины второй пары точек (если она найдена). Верхняя граница в этом случае "оставлена в качестве упражнения для читателя" :-).
Сравнение модифицированного алгоритма с (слишком) простым алгоритмом показало для нормального и квадратного равномерного распределения почти удвоение времени обработки и уменьшение средней ошибки с 0,6% до 0,03% (порядок величины). . Дальнейший перезапуск со средней точки приводит к немного лучшей средней ошибке, но почти равной максимальной ошибке.
ИЗМЕНИТЬ 4:
Мне еще нужно изучить эту статью, но она похоже, что 20%, которые я нашел с помощью компаса и линейки, на самом деле составляют 1-1/√(5-2√3) ≅ 19,3%
person
Community
schedule
31.05.2013