Ефективно знайти сусідів 1-го порядку 200k багатокутників


14

Для кожної з 208 781 блок-груп перепису я хотів би отримати ідентифікатори FIPS усіх своїх сусідів першого порядку. У мене всі межі TIGER завантажені і об'єднані в єдиний файл формату 1 Гб.

Я спробував сценарій ArcPython, який використовує SelectLayerByLocation для BOUNDARY_TOUCHES по своїй суті, але це займає більше 1 секунди для кожної групи блоків, що повільніше, ніж я хотів би. Це навіть після того, як я обмежу пошук SelectLayerByLocation блокувати групи в одному стані. Я знайшов цей сценарій , але він також використовує SelectLayerByLocation внутрішньо, так що це не швидше.

Рішення не повинно бути на основі дуги - я відкритий для інших пакетів, хоча мені зручніше кодувати Python.


2
Починаючи з версії 9.3, у панелі інструментів просторової статистики є інструменти для цього. Починаючи з 10.0, вони дуже ефективні. Я пригадую, що подібну операцію виконував на файлі форм порівнянного розміру (всі блоки в одному стані), і він завершився за 30 хвилин, 15 - це лише для вводу / виводу диска - і це було два роки тому на значно повільнішій машині. Доступний і вихідний код Python.
whuber

Який геопроцесорний інструмент у просторовій статистиці ви використовували?
dmahr

1
Я забуваю його назву; спеціально для створення таблиці багатокутних відносин сусідів. Довідкова система рекомендує вам створити цю таблицю перед тим, як запустити будь-який із інструментів просторової статистики на основі сусідів, щоб інструменти не потребували перерахування цієї інформації під час кожного запуску. Значним обмеженням, принаймні у версії 9.x, було те, що вихід був у форматі .dbf. Для великого вхідного формфайлу, який не працюватиме, у такому випадку вам доведеться або розбити операцію на шматки, або зламати код Python для виведення в кращому форматі.
whuber


Так, це все. Код Python повністю використовує внутрішні можливості ArcGIS (які використовують просторові індекси), що робить алгоритм досить швидким.
whuber

Відповіді:


3

Якщо у вас є доступ до ArcGIS 10.2 для робочого столу чи, можливо, раніше, я вважаю, що інструмент " Сусідність полігонів (аналіз)" , який:

Створює таблицю зі статистикою на основі послідовності багатокутника (перекриття, збігаються ребра або вузли).

Полігони-сусіди

зараз це може значно полегшити це завдання.


Спасибі, PolyGeo. Я оновив прийняту відповідь, щоб інструмент «Полігонові сусіди» отримав трохи більше опромінення. Це, безумовно, більш надійний, ніж мій ручний метод на основі Python, хоча я не впевнений у порівнянні масштабованості з великими наборами даних.
dmahr

В даний час я використовую 10.3, і це не вдається на моєму файлі форм з переписними блоками ~ 300 Кб.
soandos

@soandos Це здається, що це може бути варто вивчити / задати як нове запитання.
PolyGeo

8

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

w = pysal.rook_from_shapefile("../pysal/examples/columbus.shp")

або

w = pysal.queen_from_shapefile("../pysal/examples/columbus.shp")

Зверніться до документів для отримання додаткової інформації.


3

Просто оновлення. Дотримуючись порад Вубера, я виявив, що генерувати матрицю просторових ваг просто використовують петлі та словники Python для визначення сусідів. Я відтворив процес нижче.

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

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

# Create dictionary of vertex coordinate : [...,IDs,...]
BlockGroupVertexDictionary = {}
BlockGroupCursor = arcpy.SearchCursor(BlockGroups.shp)
BlockGroupDescription = arcpy.Describe(BlockGroups.shp)
BlockGroupShapeFieldName = BlockGroupsDescription.ShapeFieldName
#For every block group...
for BlockGroupItem in BlockGroupCursor :
    BlockGroupID = BlockGroupItem.getValue("BKGPIDFP00")
    BlockGroupFeature = BlockGroupItem.getValue(BlockGroupShapeFieldName)
    for BlockGroupPart in BlockGroupFeature:
        #For every vertex...
        for BlockGroupPoint in BlockGroupPart:
            #If it exists (and isnt empty interior hole signifier)...
            if BlockGroupPoint:
                #Create string version of coordinate
                PointText = str(BlockGroupPoint.X)+str(BlockGroupPoint.Y)
                #If coordinate is already in dictionary, append this BG's ID
                if PointText in BlockGroupVertexDictionary:
                    BlockGroupVertexDictionary[PointText].append(BlockGroupID)
                #If coordinate is not already in dictionary, create new list with this BG's ID
                else:
                    BlockGroupVertexDictionary[PointText] = [BlockGroupID]
del BlockGroupItem
del BlockGroupCursor


#Create dictionary of ID : [...,neighbors,...]
BlockGroupNeighborDictionary = {}
BlockGroupCursor = arcpy.SearchCursor(BlockGroups.shp)
BlockGroupDescription = arcpy.Describe(BlockGroups.shp)
BlockGroupShapeFieldName = BlockGroupDescription.ShapeFieldName
#For every block group
for BlockGroupItem in BlockGroupCursor:
    ListOfBlockGroupNeighbors = []
    BlockGroupID = BlockGroupItem.getValue("BKGPIDFP00")
    BlockGroupFeature = BlockGroupItem.getValue(BlockGroupShapeFieldName)
    for BlockGroupPart in BlockGroupFeature:
        #For every vertex
        for BlockGroupPoint in BlockGroupPart:
            #If it exists (and isnt interior hole signifier)...
            if BlockGroupPoint:
                #Create string version of coordinate
                PointText = str(BlockGroupPoint.X)+str(BlockGroupPoint.Y)
                if PointText in BlockGroupVertexDictionary:
                    #Get list of block groups that have this point as a vertex
                    NeighborIDList = BlockGroupVertexDictionary[PointText]
                    for NeighborID in NeighborIDList:
                        #Don't add if this BG already in list of neighbors
                        if NeighborID in ListOfBGNeighbors:
                            pass
                        #Add to list of neighbors (as long as its not itself)
                        elif NeighborID != BlockGroupID:
                            ListOfBGNeighbors.append(NeighborID)
    #Store list of neighbors in blockgroup object in dictionary
    BlockGroupNeighborDictionary[BlockGroupID] = ListOfBGNeighbors

del BlockGroupItem
del BlockGroupCursor
del BlockGroupVertexDictionary

Зрозумівши, я розумію, що я міг би використати інший метод для другої частини, який не потребував повторного перегляду форматного файлу. Але це те, що я використав, і він працює досить добре навіть для 1000 груп блоків одночасно. Я не намагався робити це з усіма США, але це може бути виконано для цілого штату.


2

Альтернативою може бути використання PostgreSQL та PostGIS . Я задав кілька запитань щодо виконання подібних розрахунків на цьому веб-сайті:

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


1

Лише декілька коментарів ... метод esri / ArcGIS в даний час використовує словники для зберігання інформації, але основні обчислення виконуються в C ++ за допомогою інструменту Polygon Neighbors. Цей інструмент створює Таблицю, яка містить інформацію про суміжність, а також необов'язкові аттри, такі як довжина загальної межі. Ви можете використовувати інструмент генерування матриць просторових ваг, якщо хочете зберігати та згодом повторно використовувати інформацію знову і знову. Ви також можете використовувати цю функцію в WeightsUtilities, щоб створити словник [випадковий доступ] з інформацією про суміжність:

contDict = polygonNeighborDict(inputFC, masterField, contiguityType = "ROOK")

де inputFC = будь-який тип класу функцій багатокутника, masterField - це поле "унікальний ідентифікатор" цілих чисел і contiguityType в {"ROOK", "QUEEN"}.

Есрі намагаються пропустити табличний аспект для користувачів Python та перейти безпосередньо до ітератора, який зробить багато випадків використання набагато швидшими. PySAL та пакет spdep в R - це фантастичні альтернативи [див . Відповідь radek] . Я думаю, що вам потрібно використовувати shapefiles як формат даних у цих пакунках, який відповідає формату вводу / цього потоку. Не впевнені, як вони мають справу з перекриттями полігонів, а також полігонами в межах багатокутників. Створюйте SWM, а також описану нами функцію вважатимуть ці просторові відносини сусідами "ROOK" AND "QUEEN".

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