Чому сценарій ArcPy повільний?


12

У мене є простий скрипт 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

Якщо вам потрібно створити другий курсор 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:
...

Це було саме це. Дякую. а потім я використовую .reset () на своєму другому курсорі кожен раз, коли я хочу його перейти? Здається, зараз він проходить лише через курсор 1 раз.
EmdyP

Гм, вам не потрібно буде скидати рядки. Переконайтеся, що ви видаляєте як об’єкти рядків, так і об’єкти курсору в кінці сценарію. Смішні речі можуть трапитися, якщо цього не зробити.
Джейсон

Я думаю , що курсор внутрішнього циклу в дійсно потрібно бути скидаються кожен раз , якщо йти по цьому шляху. Дивіться мою відповідь щодо альтернативи.
blah238

10

Проблема з відповіддю @ Джейсона (і вашим оригінальним підходом) полягає в тому, що він не використовує просторовий індекс і вимагає вкладеного циклу з двома курсорами, який буде ставати експоненціально повільніше, оскільки кількість очок збільшується.

Альтернативний робочий процес, який може бути швидшим, все ж дозволяючи оновити точковий клас функцій на місці (просторовий приєднання виводить лише новий клас функцій, а не оновлення існуючого), можливо:

  1. Використовуйте Spatial Join, щоб створити проміжний (можливо, в пам'яті) клас функцій
  2. Використовуйте Додати приєднатися, щоб приєднати проміжний клас функцій до існуючого класу точок функції
  3. Використовуйте поле «Обчислити» або « UpdateCursor», щоб скопіювати значення в полем, що з'єдналося, в поле в існуючому класі класу функцій.

2
Мені подобається цей альтернативний робочий процес - мені це подобається, хоч я не задавав питання, я все ще вчу нові способи робити тут справи.
Джейсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.