Самый быстрый способ пространственно объединить точку CSV с помощью многоугольника Shapefile

19

У меня есть CSV-файл на 1 миллиард точек и шейп-файл с 5000 полигонов. Какой самый быстрый способ пространственно соединить точки и полигоны? Для каждой точки мне нужно получить идентификатор полигона. (Полигоны не перекрываются.)

Обычно я загружаю оба набора данных в PostGIS. Есть ли более быстрый способ сделать работу?

Я ищу решение с открытым исходным кодом.

Подземье
источник

Ответы:

16

Если к «самому быстрому» относится количество потраченного вами времени, решение будет зависеть от того, какое программное обеспечение вам удобно и может использоваться в срочном порядке. Следующие замечания, следовательно, сосредоточены на идеях для достижения максимально быстрого времени вычислений .

Если вы используете постоянную программу, почти наверняка лучшее, что вы можете сделать, - это предварительно обработать полигоны для настройки структуры данных точка-полигон, такой как дерево KD или дерево квадрантов, производительность которого обычно будет O (log (V). ) * (N + V)) где V - общее количество вершин в многоугольниках, а N - количество точек, потому что структуре данных потребуется не менее O (log (V) * V) усилий для создания, а затем будет должны быть проверены для каждой точки при стоимости за точку O (log (V)).

Вы можете добиться значительно большего успеха, сначала установив сетку полигонов, используя предположение об отсутствии перекрытий. Каждая ячейка сетки либо целиком находится во внутренней части многоугольника (включая внутреннюю часть «универсального многоугольника»), и в этом случае пометьте ячейку идентификатором многоугольника, либо она содержит один или несколько ребер многоугольника. Стоимость этой растеризации, равная количеству ячеек сетки, на которые ссылаются при растеризации всех ребер, составляет O (V / c), где c - размер ячейки, но неявная константа в нотации big-O мала.

(Одним из достоинств этого подхода является то, что вы можете использовать стандартные графические процедуры. Например, если у вас есть система, которая (а) будет рисовать многоугольники на виртуальном экране, используя (b) отдельный цвет для каждого многоугольника и (с) позволяет Вы должны прочитать цвет любого пикселя, к которому хотите обратиться, у вас получилось.)

С этой сеткой предварительно экранируйте точки, вычисляя ячейку, содержащую каждую точку (операция O (1), требующая всего несколько часов). Если точки не сгруппированы вокруг границ многоугольника, это обычно оставляет только около O (c) точек с неоднозначными результатами. Таким образом, общая стоимость построения сетки и предварительной проверки составляет O (V / c + 1 / c ^ 2) + O (N). Вы должны использовать какой-то другой метод (например, любой из рекомендованных до сих пор) для обработки оставшихся точек (то есть тех, которые близки к границам полигонов), за счет O (log (V) * N * c) ,

По мере того как c становится меньше, все меньше и меньше точек будут находиться в одной и той же ячейке сетки с ребром, и поэтому все меньше и меньше потребуется последующей обработки O (log (V)). В противовес этому необходимо хранить O (1 / c ^ 2) ячеек сетки и тратить O (V / c + 1 / c ^ 2) время на растеризацию полигонов. Поэтому будет оптимальный размер сетки c. При его использовании общая вычислительная стоимость составляет O (log (V) * N), но неявная постоянная обычно намного меньше, чем при использовании стандартных процедур, из-за скорости O (N) предварительного скрининга.

20 лет назад я проверил этот подход (используя равномерно расположенные точки по всей Англии и на море и используя относительно грубую сетку из 400К ячеек, предлагаемых видеобуферами того времени) и получил ускорение на два порядка по сравнению с наилучшим опубликованным алгоритмом, который я мог находить. Даже когда полигоны маленькие и простые (например, треугольники), вы практически уверены в ускорении на порядок.

По моему опыту, вычисления были настолько быстрыми, что вся операция была ограничена скоростями ввода-вывода данных, а не процессором. Предвидя, что ввод-вывод может стать узким местом, вы достигнете очень быстрых результатов, сохранив точки в максимально сжатом формате, чтобы минимизировать время чтения данных. Также подумайте о том, как следует хранить результаты, чтобы можно было ограничить запись на диск.

Whuber
источник
6
Очень хороший момент времени, потраченный на реализацию решения, по сравнению с вычислительным временем. Потребовалось много времени, чтобы найти оптимальное решение, только если вы реализуете эту экономию за счет оптимизации (особенно с точки зрения работодателя).
Саша Иветик
5

Со своей стороны, я бы, вероятно, загрузил бы данные CSV в файл shp, а затем написал бы скрипт на python, используя shapefile и shapely, чтобы получить содержащийся идентификатор многоугольника и обновить значение поля.

Я не знаю, быстрее ли geotools и JTS, чем shapefile / shapely ... Нет времени, чтобы проверить это!

редактирование : Кстати, преобразование CSV в формат шейп файла, вероятно, не требуется, так как значения могут быть легко отформатированы для тестирования с пространственными объектами из вашего шейп файла полигона.

Симо
источник
4
Я бы напрямую загружал данные с помощью csv reader и заполнял пространственный индекс Rtree . Комбинация Rtree и Shapely имеет впечатляющую производительность (намного лучше, чем PostGIS; я не могу сравнить с JTS, так как не знаю Java).
Майк Т
2
Хорошая идея, если вам не нужно хранить все 1b точек в памяти одновременно. Как минимум 16 байтов на точку (X / Y), вы смотрите на 16 ГБ данных. Если Rtree построит индекс на локальном хранилище, это определенно улучшит производительность. Импорт точек 1b в один шейп-файл также не будет работать. Шейп-файлы состояния спецификации OGR ограничены 8 ГБ (рекомендуется 4 ГБ). Форма с одной точкой использует 20 байтов.
Саша Иветич
4

В итоге я преобразовал полигоны в растр и сделал выборку в точечных позициях. Поскольку мои полигоны не перекрывались и высокая точность не была необходима (полигоны представляли классы землепользования, а их границы все равно считались довольно неопределенными), это было самое эффективное по времени решение, которое я мог придумать.

Подземье
источник
3

Я бы быстро написать небольшую программу Java на основе читателя шейп из GeoTools и операция содержит в JTS . Я не знаю, как быстро это может быть ...

жюльен
источник
1
Если у вас есть данные в PostGIS, GeoTools может использовать индексы гистограммы и т. Д.
Ian Turton
3

Используйте Spatialite .

Загрузите графический интерфейс. Вы можете открыть как Shapefile, так и CSV как виртуальные таблицы. Это означает, что вы на самом деле не импортируете их в базу данных, но они отображаются в виде таблиц, и вы можете быстро присоединиться и запросить их любым удобным вам способом.

Шон
источник
3

Вы можете сделать это довольно быстро, используя OGR в C / C ++ / Python (Python должен быть самым медленным из 3). Проходите по всем полигонам и устанавливайте фильтр для точек, проходите по отфильтрованным точкам, и вы будете знать, что каждая из точек, через которую вы проходите, будет принадлежать текущему многоугольнику. Вот пример кода на python с использованием OGR, который будет проходить через полигоны и фильтровать точки соответственно. Код C / C ++ будет выглядеть примерно так, и я думаю, вы получите значительное увеличение скорости по сравнению с Python. Вам нужно будет добавить несколько строк кода для обновления CSV по мере продвижения:

from osgeo import ogr
from osgeo.gdalconst import *

inPolyDS = ogr.Open("winnipeg.shp", GA_ReadOnly)
inPolyLayer = inPolyDS.GetLayer(0)
inPointDS = ogr.Open("busstops.vrt", GA_ReadOnly)   
inPointLayer = inPointDS.GetLayerByName("busstops")

inPolyFeat = inPolyLayer.GetNextFeature()
while inPolyFeat is not None:
  inPtFeat = inPointLayer.GetNextFeature()
  while inPtFeat is not None:
    ptGeom = inPtFeat.GetGeometryRef()
    # Do work here...

    inPtFeat = inPointLayer.GetNextFeature()

  inPolyFeat = inPolyLayer.GetNextFeature()

Файл VRT (busstops.vrt):

<OGRVRTDataSource>
  <OGRVRTLayer name="busstops">
    <SrcDataSource>busstops.csv</SrcDataSource>
    <GeometryType>wkbPoint</GeometryType>
    <LayerSRS>WGS84</LayerSRS>
    <GeometryField encoding="PointFromColumns" x="X" y="Y" reportSrcColumn="FALSE" />
  </OGRVRTLayer>
</OGRVRTDataSource>

CSV-файл (busstops.csv):

FID,X,Y,stop_name
1,-97.1394781371062,49.8712241633646,Southbound Osborne at Mulvey

Файл CSVT (busstops.csvt, OGR нужен для определения типов столбцов, иначе он не будет выполнять пространственный фильтр):

Integer,Real,Real,String
Саша Иветик
источник
2
Разве это не проходит через 1 млрд. Точек 5000 раз (по одному разу для каждого полигона)?
Подземье
Пространственный индекс является абсолютной необходимостью . Я упоминал Rtree раньше, и я упомяну это снова!
Майк Т
-1

может попробовать csv2shp csv2shp

интересно узнать, в какой отрасли находится CSV с миллиардным баллом?

sirgeo
источник
1
аналогичный вопрос был задан на плате stackoverflow по
поводу