Teilen von Polygonen in * n * Anzahl gleich großer Gruppen mit ArcPy?

10

Eine meiner Aufgaben bei der Arbeit ist es, Pakete in Gruppen aufzuteilen. Diese Gruppen werden von Agenten verwendet, um mit den Eigentümern zu sprechen. Ziel ist es, die Arbeit des Agenten zu vereinfachen, indem nahe beieinander liegende Pakete gruppiert und die Pakete in gleiche Anzahl aufgeteilt werden, damit die Arbeit gleichmäßig verteilt wird. Die Anzahl der Agenten kann von einem Paar bis zu 10+ schwanken.

Derzeit führe ich diese Aufgabe manuell aus, möchte aber den Prozess nach Möglichkeit automatisieren. Ich habe verschiedene ArcGIS-Tools untersucht, aber keines scheint meinen Anforderungen zu entsprechen. Ich habe ein Skript (in Python) ausprobiert, das near_analysisPolygone verwendet und auswählt, aber es ist ziemlich zufällig und dauert ewig, um ein halbkorrektes Ergebnis zu erzielen, dessen Korrektur dann länger dauert, als wenn ich von Anfang an alles manuell gemacht hätte.

Gibt es eine zuverlässige Methode, um diese Aufgabe zu automatisieren?

Ergebnisbeispiel (hoffentlich ohne die gelbe Unterteilung):

Geteilte Pakete

Emil Brundage
quelle
Haben Sie sich mit der Standortzuordnungsanalyse befasst? help.arcgis.com/de/arcgisdesktop/10.0/help/index.html#/…
Phloem
Haben Sie versucht, eine Gruppierungsanalyse (räumliche Statistik) durchzuführen?
FelixIP
Ich habe auch einen Pseudocode der tatsächlichen Prozedur gepostet, die ich verwende, um zu sehen, ob dies helfen könnte. Gis.stackexchange.com/questions/123289/…
FelixIP
@crmackey Ich freue mich über den Link zu meiner Antwort, bin mir aber nicht sicher, wie Sie den verknüpften Code (Aufteilen von Polygonen) an dieses Problem anpassen können (Gruppieren von Polygonen).
Phloem

Antworten:

4

Originalset:

Geben Sie hier die Bildbeschreibung ein

Erstellen Sie eine Pseudokopie (CNTRL-Drag in TOC) davon und stellen Sie eine räumliche Verknüpfung eins zu viele mit dem Klon her. In diesem Fall habe ich eine Entfernung von 500 m verwendet. Ausgabetabelle:

Geben Sie hier die Bildbeschreibung ein

  1. Entfernen Sie Datensätze aus dieser Tabelle, wobei PAR_ID = PAR_ID_1 - einfach.

  2. Durchlaufen Sie die Tabelle und entfernen Sie Datensätze, wobei (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) eines darüber liegenden Datensatzes ist. Nicht so einfach, benutze acrpy.

Berechnen Sie die Einzugsgebiete (UniqID = PAR_ID). Sie sind Knoten oder Netzwerk. Verbinden Sie sie durch Linien mithilfe einer räumlichen Verknüpfungstabelle. Dies ist ein separates Thema, das sicherlich irgendwo in diesem Forum behandelt wird.

Geben Sie hier die Bildbeschreibung ein

Das folgende Skript geht davon aus, dass die Knotentabelle folgendermaßen aussieht: Geben Sie hier die Bildbeschreibung ein

Wo MUID von Paketen kam, ist P2013 ein Feld zum Zusammenfassen. In diesem Fall = 1 nur zum Zählen. [rcvnode] - Skriptausgabe zum Speichern der Gruppen-ID gleich NODEREC des ersten Knotens in der definierten Gruppe / dem definierten Cluster.

Verknüpft die Tabellenstruktur mit hervorgehobenen wichtigen Feldern

Geben Sie hier die Bildbeschreibung ein

Times speichert das Link- / Kantengewicht, dh die Reisekosten von Knoten zu Knoten. In diesem Fall gleich 1, sodass die Reisekosten für alle Nachbarn gleich sind. [fi] und [ti] sind die fortlaufende Anzahl verbundener Knoten. Um diese Tabelle zu füllen, durchsuchen Sie dieses Forum nach der Zuordnung von und zu zu verknüpfenden Knoten.

Skript angepasst für meine eigene Workbench mxd. Muss geändert und mit Ihrer Benennung der Felder und Quellen fest codiert werden:

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)

NODES LAYER FINDEN

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

GET LINKS LAYER

    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()

Ausgabebeispiel für 6 Gruppen:

Geben Sie hier die Bildbeschreibung ein

Sie benötigen das Site-Paket NETWORKX http://networkx.github.io/documentation/development/install.html

Das Skript verwendet die erforderliche Anzahl von Clustern als Parameter (6 im obigen Beispiel). Es werden Knoten- und Verknüpfungstabellen verwendet, um ein Diagramm mit gleichem Gewicht / Abstand der Verfahrkanten zu erstellen (Zeiten = 1). Es berücksichtigt die Kombination aller Knoten mit 2 und berechnet die Summe von [P2013] in zwei Gruppen von Nachbarn. Wenn das erforderliche Verhältnis erreicht ist, z. B. (6-1) / 1 bei der ersten Iteration, wird das Ziel mit reduziertem Verhältnis, dh 4 usw., bis 1 fortgesetzt. Startpunkte sind von großer Bedeutung. Stellen Sie daher sicher, dass Ihre Endknoten oben sitzen Ihrer Knotentabelle (Sortierung?) Siehe die ersten 3 Gruppen in der Beispielausgabe. Es hilft, das Schneiden von Zweigen bei jeder nächsten Iteration zu vermeiden.

Skriptanpassung für mxd:

  1. Sie müssen GEMEINSAM nicht importieren. Es ist mein eigenes Ding, das meine eigene Umgebungstabelle liest, in der theNodesLayer, theLinksLayer, linksFromI, linksToI angegeben sind. Ersetzen Sie relevante Zeilen durch Ihre eigene Benennung von Knoten und Verknüpfungsebenen.
  2. Beachten Sie, dass im Feld P2013 alles gespeichert werden kann, z. B. Anzahl der Mieter oder Paketfläche. In diesem Fall können Sie Polygone gruppieren, um ungefähr die gleiche Anzahl von Personen usw. aufzunehmen.
FelixIP
quelle
In Wirklichkeit sind Knoten- und Verknüpfungsschichten nur visuelle Dinge. Die bereinigte Tabelle der räumlichen Verknüpfung kann die Verknüpfungstabelle leicht ersetzen, da von und zu Knoten bereits zugewiesen sind. Die Polygontabelle kann leicht als Knotentabelle dienen. Fügen Sie einfach das ReceivingNode-Feld hinzu und übertragen Sie fortlaufende Nummern von dort zurück zu 'links' [FromI] und [ToI].
FelixIP
Das sieht gut aus. Vielen Dank für die Antwort. Können Sie mehr über das Warum und nicht nur das Wie erklären? Kommentare zu Ihrem Code wären riesig.
Emil Brundage
Bitte folgen Sie dem Hyperlink in meinem früheren Kommentar zu Ihrer Frage. Ich habe versucht, den Ansatz zu erklären, wenn dies das Warum ist. Ich ziehe meinen Kommentar zur Wichtigkeit des Startknotens zurück, da ich nach dem Posten der Antwort auf Ihr Q die Reihenfolge der Datensätze nach dem Zufallsprinzip geändert habe, um das Skript zu beenden. Es passierte nichts, es wurden immer noch vernünftige Ergebnisse erzielt.
FelixIP
Um die räumliche Verknüpfungstabelle zu bereinigen, reicht es aus, PAR_ID = PAR_ID_1 zu löschen, da Kante / Verknüpfung [0,2] im ungerichteten Diagramm von NETWORKX gleich Kante [2,0] ist. Ich kann ein aktualisiertes Skript veröffentlichen, nicht sicher, ob es meinen Ruf beeinträchtigen wird
FelixIP
@EmilBrundage werfen Sie einen Blick, es könnte helfen, warum Frage gis.stackexchange.com/questions/165057/…
FelixIP
2

Sie sollten das Tool "Gruppenanalyse" verwenden, um Ihr Ziel zu erreichen. Dieses Tool ist ein großartiges Tool aus der Toolbox "Raumstatistik", auf das @phloem hingewiesen hat. Sie sollten das Tool jedoch genau abstimmen, um es an Ihre Daten und Probleme anzupassen. Ich habe ein ähnliches Szenario wie das von Ihnen veröffentlichte erstellt und die Antwort nahe an Ihr Ziel gebracht.

Hinweis: Als ich das Tool unter ArcGIS 10.2 ausführte, beschwerte es sich über das fehlende Python-Paket "six". Stellen Sie also sicher, dass Sie den ersten Link installiert haben

Schritte:

  1. Fügen Sie Ihrer Polygonklasse ein Feld hinzu, das einen eindeutigen Wert enthält
  2. Fügen Sie ein weiteres Feld vom Typ Short mit dem Namen "SameGroup" hinzu.
  3. Sie Feldrechner, um diesem Feld für alle Zeilen 1 zuzuweisen. Ändern Sie einfach eine Zeile in 2. Feld hinzugefügt

  4. Stellen Sie die Werkzeugparameter "Gruppenanalyse" wie folgt ein: Gruppenanalyse

Versuchen Sie, den Parameter "Anzahl der Nachbarn" entsprechend Ihren Anforderungen zu ändern.

Ergebnis Schnappschüsse:

Beispiel für Eingabe-Polygone

Ergebnis der Gruppenanalyse

Farid Cheraghi
quelle
2
Ich habe mich vorher mit Gruppenanalyse befasst. Es geht um räumliche, aber nicht zählen, soweit ich das beurteilen kann. Alle meine Erfahrungen aus dem Lesen der Dokumentation, dem Betrachten Ihres Beispiels und dem Durchführen meiner eigenen Tests erlauben es nicht, nach der gleichen Anzahl von Polygonen zu gruppieren.
Emil Brundage
Warum müssen Sie gleich machen (natürlich für die Agenten)? Aber wenn wir diese Einschränkung hinzufügen, warum dann die Daten basierend auf der räumlichen Beziehung gruppieren (?)?
Farid Cheraghi
1
Weil der Chef es sagt. Minimieren Sie außerdem die Reisezeit.
Emil Brundage
1

Grundsätzlich möchten Sie eine Clustering-Methode gleicher Größe, damit Sie mit diesen Schlüsselwörtern im Web suchen können. Für mich gibt es eine gute Antwort auf stats.SE mit einer Python-Implementierung in einer der Antworten. Wenn Sie mit arcpy vertraut sind, sollten Sie es mit Ihren Daten verwenden können.

Sie müssen zuerst das X und Y der Schwerpunkte Ihrer Polygone berechnen, dann können Sie diese Koordinaten in das Skript eingeben und ihre Attributtabelle mit einem .da-Cursor aktualisieren.

Radouxju
quelle
Der Link, den Sie bereitstellen, scheint auf dem richtigen Weg zu sein, aber er ist im Grunde genommen in einer Sprache, die ich nicht verstehe. Für das Skript weiß ich nicht, was die Eingaben sind, und kann keine der Codierungen entschlüsseln, um genau zu verstehen, was passiert. Es gibt sehr wenig Erklärung.
Emil Brundage
0

Hallo zusammen, ich hatte ein ähnliches Problem wie dieses zuvor, also hatte ich es einige gegeben, nie ein neues angefangen, aber nur auf der anderen Seite dachte ich

EINGANGSFORM

Form eingeben

Ich dachte, Sie könnten ein Fischnetz auf der Eingabeform erstellen

Fischnetz Fischnetz mit einem Schnittpunkt Ihrer Eingabeform würde dann

Eingabe in den Bereich

Sie können dann die Fläche dieser Pakete innerhalb des neu verarbeiteten Polygons berechnen

Zu Beginn Ihres Skripts wird der Flächeneingabepolygon / n-te Betrag gleicher Größe gewünscht

Sie müssten dann die Pakete in Beziehung setzen, damit sie wissen, welche Pakete begrenzt sind.

Dann könnten Sie durch einen Zeilencursor gehen, um die Pakete zusammenzufassen

Regeln sind

* Es teilt eine Grenze zum letzten Sommer * Es wurde nicht summiert * Sobald es den als gleiche Fläche berechneten Wert überschreitet, würde es zurücktreten und dies wäre eine Gruppe * Der Prozess würde von vorne beginnen * Die letzte Gruppe könnte es sein die Summe der verbleibenden Pakete

Ich denke, die Beziehung zwischen den Paketen herzustellen, könnte die schwierige Sache sein, aber wenn dies erledigt ist, denke ich, dass es möglich sein könnte, sie zu automatisieren

Jack Walker
quelle
Ich fürchte, ich verstehe nicht, was das mit meinem Problem zu tun hat. Was hat das Zerschneiden eines Polygons mit einem Fischnetz mit der räumlichen und gleichen Gruppierung von Polygonen zu tun? Sie scheinen sich auf den Bereich zu konzentrieren, nicht zu zählen. Die Fläche (Größe) der Paketpolygone spielt keine Rolle. Unabhängig davon, wie groß oder klein ein Paket ist, ist es immer noch nur ein Eigentümer, mit dem Sie sprechen können. Siehe mein Beispiel, in dem Rot ein ländliches Gebiet ist und sich weit ausbreitet, während Orange städtisch ist und somit eine viel kleinere Gesamtfläche abdeckt.
Emil Brundage
Hallo du, sorry, ich habe deine Frage total falsch gelesen. Ich denke, Radouxju Post könnte der richtige Weg sein, aber der Link geht mir ein bisschen über den Kopf. Das Verwandeln der Polygone in Punkte erscheint logisch und gruppiert diese dann. Es könnte eine Möglichkeit geben, das Straßennetz als Entfernung vom Punkt zur Straße einzuführen, und der nächste Punkt könnte das räumliche Element definieren
Jack Walker
0

Dies ist meine Lösung für Punktereignisse. Keine Garantie, dass es immer funktioniert ...

  1. Fügen Sie auf Ihrer Punktereignisebene (Aufrufebene1) Spalten für x (doppelt), y (doppelt) und uniqueid (lange Ganzzahl) hinzu.
  2. Öffnen Sie die Attributtabelle für Ebene 1. Berechnen Sie den x-Koordinatenpunkt für x, den y-Koordinatenpunkt für y und die FID für die eindeutige ID
  3. Führen Sie das Spatial Statistics Tool> Mapping Clusters> Grouping Analysis aus
    • Legen Sie Layer1 als Eingabefunktionen fest
    • Legen Sie uniqueid als eindeutige Feld-ID fest
    • Definieren Sie die Anzahl der Gruppen (wir sagen 10)
    • Wählen Sie x und y für Analysefelder
    • Wählen Sie "NO_SPATIAL_CONSTRAINT" für räumliche Einschränkungen
    • OK klicken
  4. Führen Sie Spatial Statistics Tools> Messen geografischer Verteilungen> Mean Center aus
    • Wählen Sie Ausgabe von # 3 als Eingabefeature-Klasse
    • Wählen Sie SS_Group als Fallfeld
    • OK klicken
  5. Öffnen Sie Network Analyst> Location Allocation Tool
    • Laden Sie die Ausgabe von # 4 als Einrichtung
    • Laden Sie Layer1 als Bedarfspunkte
    • Attribute öffnen und festlegen
      • Problemtyp als Maximierung der kapazitiven Abdeckung
      • Einrichtungen zur Auswahl als 10 (von # 3 oben)
      • Standardkapazität als Gesamtzahl der Features in Ebene 1 geteilt durch die zu wählenden Einrichtungen aufgerundet (wenn also 145 Features und 10 Einrichtungen / Bereiche auf 15 festgelegt sind)
      • OK klicken
        • Lösen
        • Ihre Bedarfspunkte sollten mehr oder weniger gleichmäßig auf 10 geografische Cluster verteilt sein
LilHeb
quelle
Ich stecke bei Schritt fünf Ihrer Methode fest. Ich habe die Network Analyst-Erweiterung ausgecheckt und die Network Analyst-Symbolleiste hinzugefügt. Aber das meiste davon ist ausgegraut und ich sehe kein "Standortzuweisungs-Tool". Ich benutze 10.1.
Emil Brundage
0

Sie müssen zuerst einen Netzwerkdatensatz mithilfe Ihrer Straßen erstellen. Ich habe diese vorgeschlagene Methode ausprobiert und hatte bisher besseres Glück, dasselbe mit der Gruppierung (Schritt 3) selbst zu tun, indem ich X-, Y-Koordinaten und k-Mittelwerte für Eingabefelder verwendete (nicht perfekt, aber schneller und näher an dem, was ich bin brauchen). Ich bin offen für andere Kommentare und Rückmeldungen.

Chris
quelle