Розділення багатокутників на * n * кількість груп рівних підрахунків за допомогою ArcPy?


10

Одне з моїх завдань для роботи - розділити посилки на групи. Ці групи використовуються агентами для спілкування з власниками нерухомості. Мета - полегшити роботу агента, згрупувавши посилки, які знаходяться поруч один з одним, а також розділити посилки на рівні числа, щоб робота була розподілена рівномірно. Кількість агентів може коливатися від пари до 10+.

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

Чи існує надійний метод автоматизації цього завдання?

Приклад результатів (сподіваємось, що без поділу ми бачимо жовтий колір):

Розділені посилки


Ви вивчили аналіз розподілу місцеположення? help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/…
phloem

Ви спробували аналіз групування (просторова статистика)?
ФеліксІп

Я також опублікував псевдокод фактичної процедури, яку я використовую, подивіться, чи може це допомогти gis.stackexchange.com/questions/123289/…
FelixIP

@crmackey Я ціную посилання на свою відповідь, але я не впевнений, як ви могли налаштувати зв'язаний код (розділення полігонів), щоб відповідати цій проблемі (групування полігонів).
флоема

Відповіді:


4

Оригінальний набір:

введіть тут опис зображення

Створіть його псевдокопію (CNTRL-перетягування в TOC) і зробіть просторовим приєднанням один до багатьох з клоном. У цьому випадку я використовував відстань 500м. Вихідна таблиця:

введіть тут опис зображення

  1. Видаліть записи з цієї таблиці, де PAR_ID = PAR_ID_1 - просто.

  2. Ітерація через таблицю та видалення записів, де (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) будь-якого запису над нею. Не так просто, використовуйте acrpy.

Обчисліть центроїди водозбору (UniqID = PAR_ID). Вони є вузлами або мережею. З'єднайте їх лініями за допомогою просторової таблиці приєднання. Ця окрема тема, безумовно, висвітлена десь на цьому форумі.

введіть тут опис зображення

Сценарій нижче передбачає, що таблиця вузлів виглядає так: введіть тут опис зображення

де MUID прийшов з посилок, P2013 - поле для підбиття підсумків. У цьому випадку = 1 лише для підрахунку. [rcvnode] - вихід скрипта для зберігання ідентифікатора групи, рівного NODEREC першого вузла у визначеній групі / кластері.

Посилання таблиці структури з важливими полями виділено

введіть тут опис зображення

Час зберігає посилання / вага краю, тобто вартість проїзду від вузла до вузла. У цьому випадку дорівнює 1, так що вартість проїзду для всіх сусідів однакова. [fi] і [ti] - послідовна кількість з'єднаних вузлів. Щоб заповнити цю таблицю, знайдіть на цьому форумі інформацію про те, як призначити посилання та вузли для посилання.

Сценарій, налаштований на мій робочий стіл mxd. Повинно бути зміненим, жорстко закодованим з назвою полів та джерел:

import arcpy, traceback, os, sys,time
import itertools as itt
scriptsPath=os.path.dirname(os.path.realpath(__file__))
os.chdir(scriptsPath)
import COMMON
sys.path.append(r'C:\Users\felix_pertziger\AppData\Roaming\Python\Python27\site-packages')
import networkx as nx
RATIO = int(arcpy.GetParameterAsText(0))

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
mxd = arcpy.mapping.MapDocument("CURRENT")
theT=COMMON.getTable(mxd)

ЗНАЙТИ РОЗУМИ РОЗУМ

theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)

ПОТРІБНЕ ПОСИЛАННЯ

    theLinksLayer = COMMON.getInfoFromTable(theT,9)
    theLinksLayer = COMMON.isLayerExist(mxd,theLinksLayer)
    arcpy.SelectLayerByAttribute_management(theLinksLayer, "CLEAR_SELECTION")        
    linksFromI=COMMON.getInfoFromTable(theT,14)
    linksToI=COMMON.getInfoFromTable(theT,13)
    G=nx.Graph()
    arcpy.AddMessage("Adding links to graph")
    with arcpy.da.SearchCursor(theLinksLayer, (linksFromI,linksToI,"Times")) as cursor:
            for row in cursor:
                (f,t,c)=row
                G.add_edge(f,t,weight=c)
            del row, cursor
    pops=[]
    pops=arcpy.da.TableToNumPyArray(theNodesLayer,("P2013"))
    length0=nx.all_pairs_shortest_path_length(G)
    nNodes=len(pops)
    aBmNodes=[]
    aBig=xrange(nNodes)
    host=[-1]*nNodes
    while True:
            RATIO+=-1
            if RATIO==0:
                    break
            aBig = filter(lambda x: x not in aBmNodes, aBig)
            p=itt.combinations(aBig, 2)
            pMin=1000000
            small=[]
            for a in p:
                    S0,S1=0,0
                    for i in aBig:
                            p=pops[i][0]
                            p0=length0[a[0]][i]
                            p1=length0[a[1]][i]
                            if p0<p1:
                                    S0+=p
                            else:
                                    S1+=p
                    if S0!=0 and S1!=0:
                            sMin=min(S0,S1)                        
                            sMax=max(S0,S1)
                            df=abs(float(sMax)/sMin-RATIO)
                            if df<pMin:
                                    pMin=df
                                    aBest=a[:]
                                    arcpy.AddMessage('%s %i %i' %(aBest,sMax,sMin))
                            if df<0.005:
                                    break
            lSmall,lBig,S0,S1=[],[],0,0
            arcpy.AddMessage ('Ratio %i' %RATIO)
            for i in aBig:
                    p0=length0[aBest[0]][i]
                    p1=length0[aBest[1]][i]
                    if p0<p1:
                            lSmall.append(i)
                            S0+=p0
                    else:
                            lBig.append(i)
                            S1+=p1
            if S0<S1:
                    aBmNodes=lSmall[:]
                    for i in aBmNodes:
                            host[i]=aBest[0]
                    for i in lBig:
                            host[i]=aBest[1]
            else:
                    aBmNodes=lBig[:]
                    for i in aBmNodes:
                            host[i]=aBest[1]
                    for i in lSmall:
                            host[i]=aBest[0]

    with arcpy.da.UpdateCursor(theNodesLayer, "rcvnode") as cursor:
            i=0
            for row in cursor:
                    row[0]=host[i]
                    cursor.updateRow(row)
                    i+=1

            del row, cursor
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

Приклад результату для 6 груп:

введіть тут опис зображення

Вам знадобиться пакет сайту NETWORKX http://networkx.github.io/documentation/development/install.html

Сценарій приймає необхідну кількість кластерів як параметр (6 у прикладі вище). За допомогою таблиць вузлів та посилань можна скласти графік з однаковою вагою / відстані країв проїзду (раз = 1). Він розглядає поєднання всіх вузлів по 2 та обчислює загальну кількість [P2013] у двох групах сусідів. Коли досягається необхідне співвідношення, наприклад (6-1) / 1 при першій ітерації, продовжується із зменшеним цільовим співвідношенням, тобто 4 і т.д. таблиці ваших вузлів (сортування?) Дивіться перші 3 групи у прикладі виведення. Це допомагає уникнути «зрізання гілок» при кожній наступній ітерації.

Настроювання сценарію для роботи з mxd:

  1. вам не потрібно імпортувати COMMON. Це моя власна річ, яка читає власну таблицю оточення, де вказані theNodesLayer, theLinksLayer, linksFromI, linksToI. Замініть відповідні рядки власним називанням вузлів та шарів посилань.
  2. Зауважте, що поле P2013 може зберігати будь-що, наприклад кількість орендарів або ділянку посилки. Якщо це так, ви можете згрупувати багатокутники, щоб вмістити приблизно рівну кількість людей тощо.

Насправді вузли та шари зв’язків - це лише візуальні речі. Очищена таблиця просторового з'єднання може легко замінити таблицю посилань, оскільки від і до вузлів вже призначені. Таблиця полігонів може легко виконувати функцію таблиці вузлів, просто додайте поле ReceivingNode і перенесіть з нього послідовні номери на "посилання" [FromI] та [ToI].
FelixIP

Це добре виглядає. Дякую за відповідь. Чи можете ви пояснити більше чому, а не лише як? Коментарі до вашого коду були б величезними.
Брюндаж Еміля

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

Для очищення просторової таблиці з'єднання достатньо видалити PAR_ID = PAR_ID_1, оскільки край / посилання [0,2] у ненаправленому графіку NETWORKX дорівнює краю [2,0]. Я можу розмістити оновлений сценарій, не впевнений, чи вплине це на мою репутацію
FelixIP

@EmilBrundage подивіться, це може допомогти чому питання gis.stackexchange.com/questions/165057/…
FelixIP

2

Для досягнення поставленої мети слід скористатися інструментом «Груповий аналіз». Цей інструмент - це чудовий інструмент із інструментальної області «просторової статистики», як вказував @phloem. Однак вам слід точно налаштувати інструмент для адаптації до ваших даних та проблеми. Я створив подібний сценарій, як той, який ви розмістили, і отримав відповідь, близьку до вашої мети.

Підказка: Використовуючи ArcGIS 10.2, коли я запускав інструмент, він скаржився на відсутній пакет python "шість". Тому переконайтеся, що у вас встановлено перше Посилання

Кроки:

  1. Додайте поле до класу полігонів, щоб мати унікальне значення
  2. Додайте інше поле типу Коротке з назвою, наприклад, "SameGroup"
  3. ви калькулятор поля, щоб призначити 1 цьому полі для всіх рядків. просто поміняйте один ряд на 2. Додане поле

  4. Встановіть параметри інструмента "Аналіз групи" таким чином: Груповий аналіз

спробуйте змінити параметр "Кількість сусідів" відповідно до ваших потреб.

Знімки результатів:

Зразки вхідних полігонів

Результат групового аналізу


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

Чому вам потрібно зробити рівним (поза курсом для агентів)? Але якщо ми додамо це обмеження, тоді навіщо кластеризувати (групувати) дані на основі просторових відносин !?
Фарид Черагі

1
Бо бос так говорить. Також мінімізуйте час подорожі.
Брюндаж Еміля

1

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

Спочатку потрібно обчислити X і Y центроїдів полігонів, потім ви можете ввести ці координати в сценарій і оновити їх таблицю атрибутів за допомогою курсору .da.


Посилання, яке ви надаєте, схоже, що на правильному шляху, але в основному мовою, яку я не розумію. Для сценарію я не знаю, що таке входи, і не можу розшифрувати жодне з кодування, щоб зрозуміти, що саме відбувається. Там дуже мало пояснень.
Брюндаж Еміля

0

Привіт, там у мене була подібна проблема, як у цьому раніше, тому я дав їй щось, хоча, ніколи не починав іншого, але тільки з боку торі, я думав

ВХОДНІЙ ШАФ

Форма введення

Я думав, що ви можете створити рибну мережу на формі введення

сітка ажурна сітка з пересічною вами формою введення буде тоді

вхід у область

Потім можна обчислити площу цих посилок всередині щойно обробленого багатокутника

На початку вашого сценарію область введення полігону / n кількість потрібних рівних розмірів

Тоді вам знадобиться спосіб зв’язку посилок, щоб вони знали про ті, що межують.

Потім ви можете пройти курсор рядків підсумовування посилок

Правила буття

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

Я думаю, що встановлення відносин між посилками може бути хитрою справою, але як тільки це буде зроблено, я думаю, що це можна було б автоматизувати


Боюся, я не розумію, що це стосується мого питання. Що стосується розрізання багатокутника риб’ячою сіткою з групуванням багатокутників просторово і за рівними числами? Ви, здається, зосереджені на площі, не рахуєте. Площа (розмір) полігонів посилки не є фактором. Незалежно від того, наскільки велика чи маленька посилка, з одним із власників нерухомості все-таки потрібно поговорити. Дивіться мій приклад, де червоний колір - сільська територія і поширюється широко, тоді як помаранчевий - міський і так охоплює значно меншу загальну площу.
Брюндаж Еміля

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

0

Я вважаю, що розширення, яке ви шукаєте, є вирішальним. Зазвичай він використовується для виборів, а також для територій франшизи рівного розміру. (Розмір не обов'язково означає для району, це може бути будь-яка демографія)

http://www.esri.com/software/arcgis/extensions/districting

http://help.arcgis.com/en/redistricting/pdf/Districting_for_ArcGIS_Help.pdf


0

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

  1. На ваш точковий рівень подій (call call1) додайте стовпці для x (double), y (double) та unicidid (довге ціле число)
  2. Відкрити таблицю атрибутів для шару 1. Обчисліть точку координати x для x, y координатну точку для y та FID для унікального ідентифікатора
  3. Виконати інструмент просторової статистики> Складання кластерів> Аналіз групування
    • встановити рівень1 як функції введення
    • встановити унікальний ID як унікальний ідентифікатор поля
    • Визначте кількість груп (скажемо 10)
    • Виберіть х і у для полів аналізу
    • Виберіть "NO_SPATIAL_CONSTRAINT" для просторових обмежень
    • Натисніть кнопку ОК
  4. Виконати засоби просторової статистики> Вимірювання географічних розподілів> Середній центр
    • Виберіть вихідний показник №3 як клас вхідних функцій
    • Виберіть SS_Group як поле справи
    • Натисніть кнопку ОК
  5. Відкрийте мережевий аналітик> Інструмент розподілу місцеположення
    • Завантажте вихід №4 як об'єкти
    • Завантажте шар1 як пункти попиту
    • Відкрийте атрибути та встановіть
      • Тип проблеми як максимальний потенціал покриття
      • Вибір як 10 (з №3 вище)
      • Ємність за замовчуванням як загальна кількість функцій у шарі1, поділеному на об'єкти для вибору округлого (так, якщо 145 функцій та 10 об'єктів / областей, встановити як 15)
      • Натисніть кнопку ОК
        • Вирішити
        • Ваші точки попиту мають бути більш-менш рівномірно розподілені на 10 географічних кластерів

Я застряг на кроці п'ятому вашого методу. Я перевірив розширення Network Analyst і додав панель інструментів Network Analyst. Але більшість із них є сірим кольором, і я не бачу "Інструменту розподілу місцеположення". Я використовую 10.1.
Брюндаж Еміля

0

Вам потрібно буде створити мережевий набір даних спочатку, використовуючи вулиці. Я спробував цей запропонований метод, і до цього часу мені пощастило зробити те ж саме з групуванням (етап 3) самостійно, використовуючи координати X, Y та k-засоби для полів введення (не ідеально, але швидше і ближче до того, що я є потребує). Я відкритий для інших коментарів та відгуків.

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