ArcPyスクリプトが遅いのはなぜですか?


12

ポイントシェープファイル内のフィールドを、その中にあるポリゴンフィーチャからの情報で更新する簡単なarcpyスクリプトがあります。arcpyで100ポイントを実行するには9分かかりますが、arcmapでの空間結合は瞬時に行われます。この問題を解決するための迅速に確立された方法があると確信しています。誰かが私を正しい方向に向けることができますか?

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

4
どのバージョンのArcGISを使用していますか?10.1では、arcpy.da(データアクセス)モジュールにカーソルの(非常に)高速なバージョンが追加されました。
blah238

回答:


20

の2番目のカーソルを作成する必要がある場合parcels.shpは、最初のカーソルのループ外で作成します。現状では、スクリプトは行ごとに新しいカーソルオブジェクトを作成しているため、malls.shpその処理時間がすべてかかります。

...
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:
...

これはまさにそれでした。ありがとうございました。そして、私はそれを横断したいたびに2番目のカーソルで.reset()を使用しますか?カーソルを1回だけ通過するようです。
EmdyP

うーん、行をリセットする必要はないはずです。スクリプトの最後で行オブジェクトとカーソルオブジェクトの両方を削除していることを確認してください。そうしないと面白いことが起こります。
ジェイソン

このルートを使用する場合、内側のループのカーソルを毎回リセットする必要があると思います。代替案については私の答えをご覧ください。
blah238

10

@Jasonの答え(および元のアプローチ)の問題は、空間インデックスを利用せず、ポイントの数が増えると指数関数的に遅くなるネストされた2カーソルループが必要になることです。

ポイントフィーチャクラスをインプレースで更新しながら(Spatial Joinは新しいフィーチャクラスのみを出力し、既存のフィーチャクラスは更新しません)、より高速な代替ワークフローは次のとおりです。

  1. 空間結合を使用して、中間(おそらくメモリ内)フィーチャクラスを作成します
  2. 結合の追加を使用して、中間フィーチャクラスを既存のポイントフィーチャクラスに結合します
  3. フィールドの計算またはUpdateCursorを使用して、結合されたフィールドの値を既存のポイントフィーチャクラスのフィールドにコピーします。

2
私はこの代替ワークフローが好きです。質問をしなくても、ここで物事を行う新しい方法を学んでいます。
ジェイソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.