Найти все координаты в круг географических данных в Python
У меня миллионы географических точек. Для каждой из них я хочу найти все "соседние точки", то есть все остальные точки в пределах некоторого радиуса, скажем, нескольких сотен метров.
существует наивное O (N^2) решение этой проблемы---просто вычислить расстояние всех пар точек. Однако, поскольку я имею дело с правильной метрикой расстояния (географическое расстояние), должен быть более быстрый способ сделать это.
Я хотел бы сделать это в Python. Один решение, которое приходит на ум, - использовать некоторую базу данных (mySQL с ГИС-расширениями, PostGIS) и надеяться, что такая база данных позаботится об эффективном выполнении описанной выше операции с использованием некоторого индекса. Я бы предпочел что-то более простое, хотя это не требует от меня строить и изучать такие технологии.
пара очков
- я буду выполнять операцию "найти соседей" миллионы раз
- данные оставайтесь статичными
- потому что проблема в некотором смысле проста, я хотел бы видеть, что они python код, который решает его.
положите в терминах кода python, я хочу что-то вроде:
points = [(lat1, long1), (lat2, long2) ... ] # this list contains millions lat/long tuples
points_index = magical_indexer(points)
neighbors = []
for point in points:
point_neighbors = points_index.get_points_within(point, 200) # get all points within 200 meters of point
neighbors.append(point_neighbors)
2 ответов
опрокинутый Eamon, я придумал простое решение с использованием btrees, реализованных в SciPy.
from scipy.spatial import cKDTree
from scipy import inf
max_distance = 0.0001 # Assuming lats and longs are in decimal degrees, this corresponds to 11.1 meters
points = [(lat1, long1), (lat2, long2) ... ]
tree = cKDTree(points)
point_neighbors_list = [] # Put the neighbors of each point here
for point in points:
distances, indices = tree.query(point, len(points), p=2, distance_upper_bound=max_distance)
point_neighbors = []
for index, distance in zip(indices, distances):
if distance == inf:
break
point_neighbors.append(points[index])
point_neighbors_list.append(point_neighbors)
scipy
во-первых, во-первых: существуют существующие алгоритмы для выполнения таких вещей, как к-Д Дерево. Scipy имеет реализацию python cKDtree что можно найти все точки в заданном диапазоне.
Бинарный Поиск
в зависимости от того, что вы делаете, однако, реализация чего-то подобного может быть нетривиальной. Кроме того, создание дерева довольно сложно (потенциально довольно много накладных расходов), и вы можете быть возможность уйти с помощью простого взлома, который я использовал раньше:
- вычислить PCA набора данных. Вы хотите повернуть набор данных так, чтобы наиболее значительным направлением было первое, а ортогональным (менее большим) вторым направлением было, ну, второе. Вы можете пропустить это и просто выбрать X или Y, но это вычислительно дешево и обычно легко реализовать. Если вы просто выберете X или Y, выберите направление с большей дисперсией.
- сортировка точек по основным направление (назовем это направление X).
- чтобы найти ближайшего соседа данной точки, найдите индекс ближайшей точки в X с помощью двоичного поиска (если точка уже находится в вашей коллекции, вы можете уже знать этот индекс и не нуждаетесь в поиске). Итеративно посмотрите на следующие и предыдущие точки, сохраняя лучшее совпадение до сих пор и его расстояние от вашей точки поиска. Вы можете перестать смотреть, когда разница в X больше или равна расстоянию до лучшего соответствия, поэтому далеко (на практике, как правило, очень мало точек).
- чтобы найти все точки в заданном диапазоне, сделайте то же самое, что и Шаг 3, за исключением того, что не останавливайтесь, пока разница в X не превысит диапазон.
эффективно, вы делаете o(n log(N)) предварительную обработку, и для каждой точки примерно o(sqrt (N)) - или, если распределение ваших очков плохое. Если точки распределены примерно равномерно, то число точек, расположенных ближе к X, чем ближайший сосед, будет равно это менее эффективно, если много точек находятся в пределах вашего диапазона, но никогда не намного хуже, чем грубая сила.
одним из преимуществ этого метода является то, что все это исполняется в очень немногих выделениях памяти и в основном может быть сделано с очень хорошей локальностью памяти, что означает, что он работает довольно хорошо, несмотря на очевидные ограничения.
Делоне триангуляция
другая идея: a Делоне триангуляция может работать. Для триангуляции Делони задано, что ближайшим соседом любой точки является соседний узел. Интуиция заключается в том, что во время поиска вы можете поддерживать кучу (очередь приоритетов) на основе абсолютного расстояния от точки запроса. Выберите ближайшую точку, проверьте, что она находится в диапазоне, и если да, добавьте всех своих соседей. Я!--23-->подозреваемый что невозможно пропустить какие-либо моменты, как это, но вы должны смотреть на него более внимательно, чтобы быть уверенным...