Por que o script do ArcPy é lento?

12

Eu tenho um script arcpy simples para atualizar um campo em um shapefile de ponto com informações do recurso de polígono em que ele está. Demora 9 minutos para fazer 100 pontos no arcpy, mas uma junção espacial no arcmap é instantânea. Tenho certeza de que existe uma maneira rápida e estabelecida de resolver esse problema. Alguém pode me apontar na direção certa?

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
fonte
4
Em qual versão do ArcGIS você está? 10.1 adicionou o arcpy.damódulo (Acesso a dados) com versões (muito) mais rápidas dos cursores.
precisa saber é

Respostas:

20

Se você precisar criar um segundo cursor para parcels.shp, faça isso fora do loop para o seu primeiro cursor. Como está, seu script está criando um novo objeto de cursor para cada linha, na malls.shpqual está custando todo esse tempo de processamento.

...
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
fonte
Era exatamente isso. Obrigado. e então eu uso .reset () no meu segundo cursor para cada vez que eu quero atravessá-lo? Parece que agora só passa pelo cursor uma vez.
EmdyP
Hmm, você não precisa redefinir as linhas. Certifique-se de excluir os objetos de linha e de cursor no final do script. Coisas engraçadas podem acontecer se você não.
9133 Jason
Eu acho que o cursor do circuito interno faz necessidade de ser repostas sempre que se você seguir esse caminho. Veja minha resposta para uma alternativa.
precisa saber é
10

O problema com a resposta de @ Jason (e sua abordagem original) é que ele não tira proveito do índice espacial e requer um loop aninhado de dois cursor que se tornará exponencialmente mais lento à medida que o número de pontos aumenta.

Um fluxo de trabalho alternativo que pode ser mais rápido e ainda permitir que você atualize a classe de recurso de ponto no local (a Junção Espacial gera apenas uma nova classe de recurso, não atualiza uma existente) pode ser:

  1. Use Junção Espacial para criar uma classe de recurso intermediária (talvez na memória)
  2. Use Add Join para associar a classe de recurso intermediária à sua classe de recurso de ponto existente
  3. Use Calcular campo ou um UpdateCursor para copiar os valores no campo associado para o campo na classe de recurso de ponto existente.
blah238
fonte
2
Gosto desse fluxo de trabalho alternativo - adoro que, embora não tenha feito a pergunta, ainda estou aprendendo novas maneiras de fazer as coisas aqui.
Jason