Pourquoi le script ArcPy est-il lent?

12

J'ai un script arcpy simple pour mettre à jour un champ dans un fichier de formes de points avec les informations de l'entité polygonale dans laquelle il se trouve. Il faut 9 minutes pour faire 100 points dans arcpy mais une jointure spatiale dans arcmap est instantanée. Je suis sûr qu'il existe un moyen rapide et établi de résoudre ce problème. Quelqu'un peut me diriger dans la bonne direction?

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
la source
4
À quelle version d'ArcGIS vous trouvez-vous? 10.1 a ajouté le arcpy.damodule (Data Access) avec des versions (beaucoup) plus rapides des curseurs.
blah238

Réponses:

20

Si vous devez créer un deuxième curseur pour parcels.shp, faites-le en dehors de la boucle de votre premier curseur. En l'état, votre script crée un nouvel objet curseur pour chaque ligne, malls.shpce qui vous coûte tout ce temps de traitement.

...
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
la source
C'était exactement ça. Je vous remercie. puis j'utilise .reset () sur mon deuxième curseur pour chaque fois que je veux le traverser? Il semble que cela ne passe que 1 fois par le curseur.
EmdyP
Hmm, vous ne devriez pas avoir besoin de réinitialiser les lignes. Assurez-vous que vous supprimez les objets ligne et les objets curseur à la fin du script. Des choses drôles peuvent arriver si vous ne le faites pas.
Jason
Je pense que le curseur de la boucle interne ne besoin d'être remis à zéro à chaque fois si vous allez dans cette voie. Voir ma réponse pour une alternative.
blah238
10

Le problème avec la réponse de @ Jason (et votre approche originale) est qu'elle ne tire pas parti de l'index spatial et nécessite une boucle imbriquée à deux curseurs qui va devenir exponentiellement plus lente à mesure que le nombre de points augmente.

Un flux de travail alternatif qui peut être plus rapide tout en vous permettant de mettre à jour la classe d'entités ponctuelles sur place (Spatial Join ne produit qu'une nouvelle classe d'entités, pas une autre existante), pourrait être de:

  1. Utiliser la jointure spatiale pour créer une classe d'entités intermédiaire (peut-être en mémoire)
  2. Utilisez Ajouter une jointure pour joindre la classe d'entités intermédiaire à votre classe d'entités ponctuelles existante
  3. Utilisez Calculer le champ ou un UpdateCursor pour copier les valeurs du champ joint dans le champ de la classe d' entités points existante.
blah238
la source
2
J'aime ce flux de travail alternatif - j'adore ça même si je n'ai pas posé la question, j'apprends toujours de nouvelles façons de faire les choses ici.
Jason