¿Por qué es lento el script ArcPy?

12

Tengo un script arcpy simple para actualizar un campo en un archivo de forma de puntos con información de la función de polígono en la que se encuentra. Se necesitan 9 minutos para hacer 100 puntos en arcpy, pero una unión espacial en arcmap es instantánea. Estoy seguro de que hay una forma rápida de resolver este problema. ¿Alguien me puede apuntar en la dirección correcta?

import took 0:00:07.085000
extent took 0:00:05.991000
one pt loop took 0:00:03.780000
one pt loop took 0:00:03.850000
one pt loop took 0:00:03.791000


import datetime
t1 = datetime.datetime.now()
import arcpy
t2 = datetime.datetime.now()
print "import took %s" %  ( t2-t1)
#set up environment
arcpy.env.workspace = "data\\"
arcpy.env.overwriteOutput = True

desc = arcpy.Describe("parcels.shp")
ext = desc.Extent
extent = (ext.XMin,ext.XMax,ext.YMin,ext.YMax)
t3 = datetime.datetime.now()
print "extent took %s" %  (t3 -t2)
fc = arcpy.CreateRandomPoints_management("", "malls.shp", "", ext, 100, "", "POINT", "")
arcpy.AddField_management("malls.shp", 'ParcelID', 'LONG')

rows = arcpy.UpdateCursor('malls.shp',"","",'ParcelID')
for row in rows:
    t4 = datetime.datetime.now()
    pt = row.Shape.getPart()
    for polyrow in arcpy.SearchCursor('parcels.shp'):
        t6 = datetime.datetime.now()
        poly = polyrow.getValue('Shape')
        if extent[0]<pt.X<extent[1] and extent[2]<pt.Y<extent[3]:
            if poly.contains(pt):
                print "works"
                row.ParcelID = polyrow.Parcels_ID
                rows.updateRow(row)
                break #we can stop looking for matches since
        t7 = datetime.datetime.now()
        "a full poly loop took %s" % (t7-t6)
    t5 = datetime.datetime.now()
    print "one pt loop took %s" % (t5-t4)


print datetime.datetime.now() -t1
EmdyP
fuente
44
¿En qué versión de ArcGIS estás? 10.1 agregó el arcpy.damódulo (Acceso a datos) con versiones (mucho) más rápidas de los cursores.
blah238

Respuestas:

20

Si necesita crear un segundo cursor para parcels.shp, hágalo fuera del bucle para su primer cursor. Tal como está, su secuencia de comandos está creando un nuevo objeto de cursor para cada fila, malls.shpque es lo que le está costando todo ese tiempo de procesamiento.

...
rows = arcpy.UpdateCursor('malls.shp',"","",'ParcelID')
polyrows = arcpy.SearchCursor('parcels.shp')
for row in rows:
    t4 = datetime.datetime.now()
    pt = row.Shape.getPart()
    for polyrow in polyrows:
...
Jason
fuente
Esto fue exactamente eso. Gracias. y luego uso .reset () en mi segundo cursor cada vez que quiero recorrerlo? Parece que solo pasa por el cursor 1 vez ahora.
EmdyP
Hmm, no deberías necesitar restablecer las filas. Asegúrese de eliminar tanto los objetos de fila como los de cursor al final del guión. Pueden pasar cosas divertidas si no lo haces.
Jason
Creo que el cursor del bucle interno hace que sea necesario restablecer cada vez que si usted va esta ruta. Vea mi respuesta para una alternativa.
blah238
10

El problema con la respuesta de @ Jason (y su enfoque original) es que no aprovecha el índice espacial y requiere un bucle anidado de dos cursores que se volverá exponencialmente más lento a medida que aumente el número de puntos.

Un flujo de trabajo alternativo que puede ser más rápido y al mismo tiempo permitirle actualizar la clase de entidad de punto en el lugar (la unión espacial solo genera una nueva clase de entidad, no actualiza una existente) podría ser:

  1. Use Spatial Join para crear una clase de entidad intermedia (quizás en memoria)
  2. Use Agregar unión para unir la clase de entidad intermedia a su clase de entidad de punto existente
  3. Use Calcular campo o un cursor de actualización para copiar los valores en el campo unido al campo en la clase de entidad de punto existente.
blah238
fuente
2
Me gusta este flujo de trabajo alternativo; me encanta que, aunque no hice la pregunta, todavía estoy aprendiendo nuevas formas de hacer las cosas aquí.
Jason