Ensemble d'origine:

Créez une pseudo-copie (CNTRL-faites glisser dans la table des matières) et faites une jointure spatiale un à plusieurs avec le clone. Dans ce cas, j'ai utilisé une distance de 500 m. Tableau de sortie:

Supprimez les enregistrements de cette table où PAR_ID = PAR_ID_1 - facile.
Parcourez la table et supprimez les enregistrements où (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) de tout enregistrement au-dessus. Pas si facile, utilisez acrpy.
Calculer les centroïdes du bassin versant (UniqID = PAR_ID). Ce sont des nœuds ou un réseau. Connectez-les par des lignes à l'aide de la table de jointure spatiale. C'est un sujet distinct qui est sûrement couvert quelque part sur ce forum.

Le script ci-dessous suppose que la table des nœuds ressemble à ceci:

où MUID provenait de colis, P2013 est le champ à résumer. Dans ce cas = 1 pour compter uniquement. [rcvnode] - sortie de script pour stocker l'ID de groupe NODEREC égal au premier nœud du groupe / cluster défini.
Lie la structure de la table avec les champs importants mis en évidence

Le temps stocke le poids de liaison / bord, c'est-à-dire le coût de déplacement d'un nœud à l'autre. Égal à 1 dans ce cas pour que le coût du voyage vers tous les voisins soit le même. [fi] et [ti] sont le nombre séquentiel de nœuds connectés. Pour remplir ce tableau, recherchez dans ce forum comment affecter des nœuds à partir de et vers des liens.
Script personnalisé pour mon propre atelier mxd. Doit être modifié, codé en dur avec votre nom des champs et des sources:
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)
TROUVER LA COUCHE DES NOEUDS
theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)
OBTENIR UNE COUCHE DE LIENS
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()
Exemple de sortie pour 6 groupes:

Vous aurez besoin du package de site NETWORKX
http://networkx.github.io/documentation/development/install.html
Le script prend le nombre requis de clusters comme paramètre (6 dans l'exemple ci-dessus). Il utilise des nœuds et des tables de liens pour créer un graphique avec un poids / une distance égaux des bords de déplacement (Times = 1). Il considère la combinaison de tous les nœuds par 2 et calcule le total de [P2013] dans deux groupes de voisins. Lorsque le ratio requis est atteint, par exemple (6-1) / 1 à la première itération, continue avec un objectif de ratio réduit, c'est-à-dire 4, etc. jusqu'à 1. Les points de départ sont d'une grande importance, alors assurez-vous que vos nœuds «finaux» sont assis en haut de votre table de nœuds (tri?) Voir les 3 premiers groupes dans l'exemple de sortie. Cela permet d'éviter les «coupures de branches» à chaque nouvelle itération.
Personnalisation du script pour travailler à partir de mxd:
- vous n'avez pas besoin d'importer COMMUN. C'est mon propre truc, qui lit ma propre table d'environnement, où theNodesLayer, theLinksLayer, linksFromI, linksToI sont spécifiés. Remplacez les lignes pertinentes par votre propre nom des couches de nœuds et de liens.
- Notez que le champ P2013 peut stocker n'importe quoi, par exemple le nombre de locataires ou la superficie de la parcelle. Si c'est le cas, vous pourriez regrouper des polygones pour contenir un nombre de personnes à peu près égal, etc.