10 votos

¿Dividir polígonos en *n* número de grupos de igual número con ArcPy?

Una de mis tareas en el trabajo es dividir los paquetes en grupos. Estos grupos serán utilizados por los agentes para hablar con los propietarios. El objetivo es facilitar el trabajo del agente agrupando las parcelas que están cerca unas de otras, así como dividir las parcelas en números iguales para que el trabajo se distribuya uniformemente. El número de agentes puede oscilar entre un par y más de 10.

Actualmente realizo esta tarea manualmente, pero me gustaría automatizar el proceso si es posible. He explorado varias herramientas de ArcGIS, pero ninguna parece adaptarse a mi necesidad. He probado un script (en python) que hace uso de near_analysis y la selección de polígonos, pero es bastante aleatorio y tarda una eternidad en conseguir un resultado semicorrecto que luego me lleva más tiempo arreglar que si lo hiciera todo manualmente desde el principio.

¿Existe algún método fiable para automatizar esta tarea?

Ejemplo de resultados (espero que sin la división que vemos en amarillo):

Divided Parcels

0 votos

¿Ha estudiado el análisis de asignación de lugares? help.arcgis.com/es/arcgisdesktop/10.0/help/index.html#/

0 votos

¿Ha probado el análisis de agrupación (estadística espacial)?

0 votos

También he publicado un pseudocódigo del procedimiento real que estoy utilizando, a ver si puede ayudar gis.stackexchange.com/questions/123289/

4voto

FelixIP Puntos 4035

Conjunto original:

enter image description here

Crear pseudo-copia (CNTRL-arrastrar en TOC) de la misma y hacer la unión espacial uno a muchos con el clon. En este caso he utilizado la distancia de 500m. Tabla de salida:

enter image description here

  1. Eliminar los registros de esta tabla donde PAR_ID = PAR_ID_1 - fácil.

  2. Recorrer la tabla y eliminar los registros en los que (PAR_ID,PAR_ID_1 )=(PAR_ID_1, PAR_ID) de cualquier registro superior. No es tan fácil, utilice acrpy.

Calcular los centroides de las cuencas (UniqID=PAR_ID). Son nodos o red. Conéctelos mediante líneas utilizando la tabla de unión espacial. Este es un tema aparte que seguramente se ha tratado en algún lugar de este foro.

enter image description here

El script de abajo asume que la tabla de nodos tiene ese aspecto: enter image description here

donde el MUID procede de las parcelas, P2013 es el campo a resumir. En este caso = 1 para el recuento solamente. [rcvnode] - script de salida para almacenar el ID de grupo igual a NODEREC del primer nodo del grupo/cluster definido.

Estructura de la tabla de enlaces con los campos importantes resaltados

enter image description here

Times almacena el peso del enlace/borde, es decir, el coste del viaje de un nodo a otro. Es igual a 1 en este caso para que el coste del viaje a todos los vecinos sea el mismo. [fi] y [ti] son el número secuencial de nodos conectados. Para rellenar esta tabla busca en este foro cómo asignar desde y hacia los nodos al enlace.

script personalizado para mi propio banco de trabajo mxd. Tiene que ser modificado, hardcoded con su nomenclatura de los campos y fuentes:

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)

ENCONTRAR NODOS CAPA

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

OBTENER LA CAPA DE ENLACES

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

Ejemplo de salida para 6 grupos:

enter image description here

Necesitará el paquete del sitio NETWORKX http://networkx.github.io/documentation/development/install.html

script toma como parámetro el número requerido de clusters (6 en el ejemplo anterior). Utiliza las tablas de nodos y enlaces para hacer un gráfico con igual peso/distancia de las aristas de viaje (Times=1). Considera la combinación de todos los nodos por 2 y calcula el total de [P2013] en dos grupos de vecinos. Cuando se consigue la relación requerida, por ejemplo (6-1)/1 en la primera iteración, continúa con un objetivo de relación reducido, es decir, 4, etc. hasta 1. Los puntos de partida son de gran importancia, así que asegúrese de que sus nodos "finales" se encuentran en la parte superior de la tabla de nodos (¿ordenación?) Vea los 3 primeros grupos en el ejemplo de salida. Esto ayuda a evitar el "corte de ramas" en cada iteración siguiente.

script personalización para trabajar desde mxd:

  1. no es necesario importar COMMON. Es mi propia cosa, que lee mi propia tabla de entorno, donde theNodesLayer, theLinksLayer, linksFromI, linksToI especificados. Reemplace las líneas pertinentes con su propia nomenclatura de los nodos y las capas de enlaces.
  2. Tenga en cuenta que el campo P2013 puede almacenar cualquier cosa, por ejemplo, el número de arrendatarios o la superficie de la parcela. Si es así, puede agrupar los polígonos para mantener un número aproximadamente igual de personas, etc.

0 votos

En realidad, las capas de nodos y enlaces son sólo cosas visuales. La tabla de unión espacial limpiada puede sustituir fácilmente a la tabla de enlaces, ya que los nodos de origen y destino ya están asignados. La tabla de polígonos, puede servir fácilmente como tabla de nodos, sólo hay que añadir el campo ReceivingNode y transferir los números secuenciales desde él a los 'enlaces' [FromI] y [ToI].

0 votos

Esto tiene buena pinta. Muchas gracias por la respuesta. ¿Puedes explicar más el por qué, y no sólo el cómo? Los comentarios sobre tu código serían enormes.

0 votos

Por favor, siga el hipervínculo en mi comentario anterior a su pregunta. He intentado explicar el enfoque, si es que esto es lo que significa "por qué". Retiro mi comentario sobre la importancia del nodo de inicio, porque después de publicar la respuesta a su pregunta, cambié al azar el orden de los registros tratando de matar script. No pasó nada, todavía produjo resultados razonables.

3voto

Farid Cher Puntos 5306

Debe utilizar la herramienta "Análisis de grupo" para lograr su objetivo. Esta herramienta es una gran herramienta de la caja de herramientas de "estadísticas espaciales" como señaló @phloem. Sin embargo, debes ajustar la herramienta para adaptarla a tus datos y a tu problema. He creado un escenario similar al que has publicado y he obtenido una respuesta cercana a tu objetivo.

Sugerencia: Utilizando ArcGIS 10.2, cuando ejecuté la herramienta, se quejó de que faltaba el paquete python "six". Así que asegúrese de tenerlo instalado primero Enlace

Pasos:

  1. Añadir un campo a su clase de polígono para mantener un valor único

  2. Añade otro campo de tipo Short con el nombre, por ejemplo, "SameGroup"

  3. su calculadora de campo para asignar 1 a este campo para todas las filas. sólo cambiar una fila a 2. Added Field

  4. Establezca los parámetros de la herramienta "Análisis de grupo" así: Group Analysis

intente cambiar el parámetro "Número de vecinos" para adaptarlo a sus necesidades.

Instantáneas de resultados:

Sample Input Polygons

Result of the Group Analysis

2 votos

He investigado antes el análisis de grupos. Se ocupa de lo espacial, pero no del recuento, por lo que sé. Toda mi experiencia de la lectura de la documentación, mirando a su ejemplo, y la realización de mis propias pruebas no permiten agrupar por un número igual de polígonos.

0 votos

¿Por qué hay que hacer iguales (fuera de curso para los agentes)? Pero si añadimos esa restricción, ¿por qué agrupar los datos en función de la relación espacial?

1 votos

Porque lo dice el jefe. Además, minimiza el tiempo de viaje.

1voto

xenny Puntos 670

Básicamente, usted quiere un método de agrupación de igual tamaño, por lo que podría buscar con estas palabras clave en la web. Para mí, hay un buena respuesta en stats.SE con una implementación de Python en una de las respuestas. Si estás familiarizado con arcpy deberías ser capaz de utilizarlo con tus datos.

Primero tienes que calcular las X e Y de los centroides de tus polígonos, luego puedes introducir estas coordenadas en el script y actualizar su tabla de atributos utilizando un cursor .da.

0 votos

El enlace que proporcionas parece que va por buen camino, pero está básicamente en un idioma que no entiendo. Para el script no sé cuáles son las entradas y no puedo descifrar nada de la codificación para entender exactamente lo que está pasando. Hay muy poca explicación.

0voto

Prashant Puntos 7184

Hola, he tenido un problema similar a este antes, así que le había dado un poco de pensamiento, nunca consiguió otro comenzó con, pero sólo en el lado thoery estaba pensando

FORMA DE ENTRADA

Input shape

Estaba pensando que se podría crear una red de pesca en la forma de entrada

fishnet red de pesca con una intersección de su forma de entrada sería entonces

input into area

A continuación, puede calcular la superficie de estas parcelas dentro del polígono recién procesado

Al comienzo de su script el polígono de entrada de área / nth cantidad de tamaños iguales quería

Entonces necesitaría una forma de relacionar las parcelas para que sean conscientes de las que están bordeadas.

Entonces podría pasar por un cursor de fila de sumar las parcelas

Las reglas son

*Comparte frontera con el último verano *No se ha sumado *Una vez que supera el valor calculado como área igual, retrocedería y este sería un grupo *El proceso volvería a empezar *El último grupo podría ser la suma de las parcelas sobrantes

Creo que establecer la relación entre los paquetes puede ser lo más complicado, pero una vez hecho esto, creo que podría ser posible automatizarlo.

0 votos

Me temo que no entiendo qué tiene que ver esto con mi problema. ¿Qué tiene que ver cortar un polígono con una red de pesca con agrupar polígonos espacialmente y por números iguales? Parece que te centras en el área, no en el recuento. El área (tamaño) de los polígonos de la parcela no es un factor. Independientemente de lo grande o pequeña que sea una parcela, sigue siendo un solo propietario con el que hay que hablar. Vea mi ejemplo donde el rojo es una zona rural y se extiende ampliamente, mientras que el naranja es urbano y por lo tanto cubre un área total mucho menor.

0 votos

Hola, lo siento, he leído mal tu pregunta. Creo que el post de radouxju podría ser el camino a seguir, pero el enlace va un poco por encima de mi cabeza. Convertir los polígonos en puntos parece lógico y luego agrupar estos. Podría haber una manera de introducir el sistema de carreteras como la distancia desde el punto a la carretera y el siguiente punto podría definir el elemento espacial

0voto

St. John Johnson Puntos 123

Creo que la extensión que busca es Districting. Suele utilizarse para las elecciones, pero también para los territorios de franquicia de igual tamaño. (El tamaño no significa necesariamente para el área, puede ser cualquier demografía)

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

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

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X