Почему скрипт ArcPy работает медленно?

12

У меня есть простой скрипт arcpy, чтобы обновить поле в точечном шейп-файле с помощью информации из объекта многоугольника, в котором оно находится. Для создания 100 точек в arcpy требуется 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
EmdyP
источник
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

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

Альтернативный рабочий процесс, который может быть более быстрым, но при этом позволяет обновлять класс точечных объектов на месте (Spatial Join выводит только новый класс пространственных объектов, а не обновляет существующий), может быть следующим:

  1. Используйте Spatial Join для создания промежуточного (возможно, в памяти) класса объектов
  2. Используйте Add Join, чтобы присоединить промежуточный класс объектов к существующему классу точечных объектов.
  3. Используйте Calculate Field или UpdateCursor, чтобы скопировать значения в объединенном поле в поле в существующем классе точечных объектов.
blah238
источник
2
Мне нравится этот альтернативный рабочий процесс - мне нравится это, хотя я не задавал вопрос, я все еще изучаю новые способы сделать вещи здесь.
Джейсон