Conjunto original:

Cree una pseudo-copia (CNTRL-arrastre en TOC) de ella y haga una unión espacial de uno a muchos con clon. En este caso utilicé la distancia 500m. Tabla de salida:

Eliminar registros de esta tabla donde PAR_ID = PAR_ID_1 - fácil.
Itere a través de la tabla y elimine los registros donde (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) de cualquier registro que se encuentre encima. No es tan fácil, usa acrpy.
Calcule los centroides de captación (UniqID = PAR_ID). Son nodos o red. Conéctelos por líneas usando la tabla de unión espacial. Este es un tema separado seguramente cubierto en algún lugar de este foro.

El siguiente script asume que la tabla de nodos se ve así:

donde MUID vino de las parcelas, P2013 es un campo para resumir. En este caso = 1 solo para contar. [rcvnode]: salida del script para almacenar la ID de grupo igual a NODEREC del primer nodo en el grupo / clúster definido.
Estructura de la tabla de enlaces con campos importantes resaltados

Times almacena el peso del enlace / borde, es decir, el costo de viaje de un nodo a otro. Igual 1 en este caso para que el costo de viaje a todos los vecinos sea el mismo. [fi] y [ti] son un número secuencial de nodos conectados. Para completar esta tabla, busque en este foro cómo asignar desde y hacia nodos para vincular.
Script personalizado para mi propio workbench mxd. Tiene que ser modificado, codificado con su nombre 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 CAPA DE NODOS
theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)
OBTENER 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:

Necesitará el paquete de sitio NETWORKX
http://networkx.github.io/documentation/development/install.html
El script toma el número requerido de clústeres como parámetro (6 en el ejemplo anterior). Utiliza tablas de nodos y enlaces para hacer un gráfico con igual peso / distancia de los bordes 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 alcanza la proporción requerida, por ejemplo (6-1) / 1 en la primera iteración, continúa con el objetivo de proporción reducida, es decir, 4, etc. hasta 1. Los puntos de inicio son de gran importancia, así que asegúrese de que sus nodos 'finales' se encuentren en la parte superior de su tabla de nodos (¿ordenando?) Vea los primeros 3 grupos en la salida de ejemplo. Ayuda a evitar el 'corte de ramas' en cada próxima iteración.
Personalización de script para trabajar desde mxd:
- no necesitas importar COMÚN. Es lo mío, que lee mi propia tabla de entorno, donde se especifica theNodesLayer, theLinksLayer, linksFromI, linksToI. Reemplace las líneas relevantes con su propio nombre de nodos y capas de enlaces.
- Tenga en cuenta que el campo P2013 puede almacenar cualquier cosa, por ejemplo, número de inquilinos o área de parcela. Si es así, puede agrupar polígonos para contener aproximadamente el mismo número de personas, etc.