Найшвидший спосіб просторового приєднання CSV до точки з багатокутником Shapefile


19

У мене є CSV-файл на 1 мільярд точок та файл форми з приблизно 5000 полігонами. Який би був найшвидший спосіб просторового з'єднання точок та полігонів? Для кожної точки мені потрібно отримати ідентифікатор, що містить полігон. (Полігони не перетинаються.)

Зазвичай я завантажую обидва набори даних у PostGIS. Чи є більш швидкий спосіб виконати роботу?

Я шукаю рішення з відкритим кодом.

Відповіді:


16

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

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

Можна зробити набагато краще, спершу склавши багатокутники, використовуючи припущення про відсутність перекриттів. Кожна клітинка сітки або повністю знаходиться у внутрішній частині багатокутника (включаючи внутрішню частину "універсального багатокутника"), і в цьому випадку комірка позначає ідентифікатором полігона, або ж вона містить один або більше країв полігону. Вартість цієї растерізації, що дорівнює кількості осередків сітки, на які посилається при растерізації всіх ребер, становить O (V / c), де c - розмір комірки, але неявна константа в нотації big-O невелика.

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

Коли ця сітка на місці, попередньо екранізуйте точки, обчисливши комірку, що містить кожну точку (операція 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. Використовуючи це, загальні обчислювальні витрати являють собою О (балці (V) * N) , але неявна константа , як правило , способі менше , ніж при використанні консервованих процедур, пов'язаних зі швидкістю O (N) від попереднього скринінгу.

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

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


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

5

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

Я не знаю, чи швидше geotools та JTS швидше, ніж shapefile / shapely ... Не майте часу тестувати це!

редагувати : До речі, перетворення CSV у формат shapefile, ймовірно, не потрібно, оскільки значення можуть бути легко відформатовані для тестування з просторовими об'єктами з вашого формату багатокутника.


4
Я б безпосередньо завантажував дані за допомогою зчитувача csv і заповнював просторовий індекс Rtree . Поєднання Rtree і Shapely мають вражаючі показники (набагато кращі, ніж PostGIS; я не можу порівняти з JTS, оскільки не знаю Java).
Майк Т

2
Гарна ідея за умови, що вам не потрібно зберігати всі 1b точок у пам'яті одразу. Щонайменше 16 байт на точку (X / Y), ви дивитесь на 16 Гб даних. Якщо Rtree побудує індекс на локальному сховищі, то це, безумовно, підвищить продуктивність. Імпорт 1b точок до одного файлу форм також не буде працювати. Файли специфікацій OGR обмежені 8 Гб (рекомендується 4 ГБ). Форма однієї точки використовує 20 байт.
Саса Іветік

4

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



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 разів (один раз на кожен багатокутник)?
underdark

Просторовий індекс - абсолютна необхідність . Раніше я згадував про Rtree , і знову згадаю!
Майк Т

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