Tengo un shapefile que incluye 49 puntos (pozos). Quiero crear 100 redes que incluyan 20 puntos seleccionados al azar de la primera red. Cuando utilicé la herramienta de creación de puntos aleatorios, algunas redes estaban duplicadas. ¿Cómo puedo crear redes no repetitivas?
Respuestas
¿Demasiados anuncios?Dado que necesitamos compilar una lista de IDs para un SQL IN
de todos modos, usemos esa cadena como base de comparación para generar las listas únicas...
import random
import arcpy
numSets = 100
setSize = 20
sourceFC = r'D:\gis_se\pick49.shp'
outputGDB = r'D:\gis_se\picked.gdb'
# Extract all IDs
rawIDs = sorted([row[0] for row in arcpy.da.SearchCursor(sourceFC,'OID@')])
# Compile unique sets
resultSets = []
while (len(resultSets) < numSets):
candidate = list(rawIDs)
random.shuffle(candidate)
subset = ','.join([str(id) for id in sorted(candidate[:setSize])])
if (subset not in resultSets):
resultSets.append(subset)
# Export the copies to GDB (or not)
print("\n".join(sorted(resultSets)))
Al probar con "generar 10 conjuntos con 5 elegidos de entre 10" pude generar candidatos duplicados, pero cuando pasé a "generar 100 conjuntos con 20 elegidos de entre 49" no fue así, pero incluso si tu generador aleatorio es cruel, esto no generará duplicados.
Puede que esto no sea lo que está preguntando, si es así hágamelo saber.
Esto seleccionará 20 puntos al azar 20 veces sin repeticiones:
import arcpy, random
arcpy.env.overwriteOutput=True
fc = r'C:\GIS\ArcMap_default_folder\Default.gdb\jl_riks_Intersect'
oidfield = arcpy.Describe(fc).OIDFieldName
alloids = [row[0] for row in arcpy.da.SearchCursor(fc,'OID@')] #List all object ids to select from
samples = []
#Create 20 lists of 20 oids and append to samples list
for i in range(1,21):
sample = []
for j in range(1,21):
sample.append(alloids.pop(random.randint(0, len(alloids)+1)))#The oid is popped so it is removed from alloids list and cant be selected again
samples.append(sample)
for sample in samples: #For each sample of 20 oids
sql = """{0} IN{1}""".format(arcpy.AddFieldDelimiters(fc, oidfield), tuple(sample))
#'OBJECTID IN(9285, 4428, 3246, 11237, 7642, 1202, 10467, 5334, 883, 12656, 9269, 5623, 13018, 3560, 9943, 197, 11917, 6709, 246, 3659)'
arcpy.MakeFeatureLayer_management(in_features=fc, out_layer='templyr', where_clause=sql)
#Or select by attributes, Select, etc.
Aquí hay un enfoque alternativo en ModelBuilder que no requiere casi ningún código que crea los subconjuntos aleatorios:
Los datos:
El modelo:
Los resultados (de sólo 5 iteraciones a modo de ejemplo):
La clave de este modelo es utilizar los propios datos de los puntos como restricción y sembrar el generador de números aleatorios en cada iteración. Tenga en cuenta que la salida de la herramienta de cálculo de valores es una condición previa, así como la configuración del entorno de semillas para el generador de números aleatorios.
-
El iterador FOR estaba simplemente configurado para contar de 1 a 5
-
Calcular valor está configurado como se muestra:
- La creación de puntos aleatorios se configura como se muestra:
Sospecho que este enfoque, tal y como ha insinuado @Vince, generará potencialmente conjuntos idénticos, al igual que cualquier otro enfoque que puedas adoptar, algo que debes comprobar Existe la herramienta Feature Compare que podría utilizarse para comparar conjuntos de datos.