Warum ist das ArcPy-Skript langsam?

12

Ich habe ein einfaches Arcpy-Skript, um ein Feld in einem Punkt-Shapefile mit Informationen aus dem darin enthaltenen Polygon-Feature zu aktualisieren. Es dauert 9 Minuten, um 100 Punkte in arcpy zu erstellen, aber eine räumliche Verknüpfung in arcmap erfolgt sofort. Ich bin sicher, es gibt einen schnell etablierten Weg, um dieses Problem zu lösen. Kann mich jemand in die richtige Richtung weisen?

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
quelle
4
Auf welcher Version von ArcGIS befinden Sie sich? 10.1 fügte das arcpy.daModul (Datenzugriff) mit (viel) schnelleren Versionen der Cursor hinzu.
blah238

Antworten:

20

Wenn Sie einen zweiten Cursor für erstellen müssen parcels.shp, tun Sie dies außerhalb der Schleife für Ihren ersten Cursor. Derzeit erstellt Ihr Skript für jede Zeile ein neues Cursorobjekt malls.shp, das Sie die gesamte Verarbeitungszeit kostet.

...
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
quelle
Das war genau das. Vielen Dank. und dann verwende ich .reset () auf meinem zweiten Cursor für jedes Mal, wenn ich ihn durchlaufen möchte? Es scheint, als würde es jetzt nur 1 Mal durch den Cursor gehen.
EmdyP
Hmm, Sie sollten die Zeilen nicht zurücksetzen müssen. Stellen Sie sicher, dass Sie sowohl Zeilenobjekte als auch Cursorobjekte am Ende des Skripts löschen. Lustige Dinge können passieren, wenn Sie es nicht tun.
Jason
Ich denke, der Cursor der inneren Schleife muss jedes Mal zurückgesetzt werden, wenn Sie diesen Weg gehen. Siehe meine Antwort für eine Alternative.
blah238
10

Das Problem mit der Antwort von @ Jason (und Ihrem ursprünglichen Ansatz) besteht darin, dass der räumliche Index nicht ausgenutzt wird und eine verschachtelte Zwei-Cursor-Schleife erforderlich ist, die mit zunehmender Anzahl von Punkten exponentiell langsamer wird.

Ein alternativer Workflow, der möglicherweise schneller ist, während Sie die Punkt-Feature-Class weiterhin direkt aktualisieren können (Spatial Join gibt nur eine neue Feature-Class aus, keine vorhandene zu aktualisieren), könnte sein:

  1. Verwenden Sie Spatial Join , um eine Zwischen-Feature-Class (möglicherweise im Speicher) zu erstellen
  2. Verwenden Sie Join hinzufügen , um die Zwischen-Feature-Class mit Ihrer vorhandenen Punkt-Feature-Class zu verbinden
  3. Verwenden Sie Feld berechnen oder einen UpdateCursor , um die Werte im verknüpften Feld in das Feld in der vorhandenen Punkt-Feature-Class zu kopieren.
blah238
quelle
2
Ich mag diesen alternativen Workflow - ich finde es toll, dass ich, obwohl ich die Frage nicht gestellt habe, immer noch neue Wege lerne, um hier Dinge zu tun.
Jason