Como melhorar o desempenho ao usar cursores ArcGIS em Python com grandes tabelas?


10

Eu tenho uma classe de recurso de ponto bastante grande em um geodatabase de arquivo (~ 4 000 000 registros). Esta é uma grade regular de pontos com uma resolução de 100m.

Eu preciso executar um tipo de generalização nessa camada. Para isso, crio uma nova grade onde cada ponto fica no meio de 4 pontos "antigos":

 *     *     *     *
    o     o     o
 *     *     *     *
    o     o     o
 *     *     *     *

[*] = ponto da grade original - [o] = ponto da nova grade

O valor do atributo de cada novo ponto é calculado com base nos valores ponderados de seus 4 vizinhos na grade antiga. Assim, faço um loop em todos os pontos da minha nova grade e, para cada um deles, faço um loop em todos os pontos da minha grade antiga, para encontrar os vizinhos (comparando os valores de X e Y na tabela de atributos). Uma vez que quatro vizinhos foram encontrados, saímos do circuito.

Não há complexidade metodológica aqui, mas meu problema é que, com base nos meus primeiros testes, esse script durará semanas para ser concluído ...

Você vê alguma possibilidade de torná-lo mais eficiente? Algumas idéias no topo da minha cabeça:

  • Indexe os campos X e Y => fiz isso, mas não percebi nenhuma alteração significativa no desempenho
  • Faça uma consulta espacial para encontrar os vizinhos em vez de uma baseada em atributos. Isso realmente ajudaria? Que função espacial no ArcGIS deve fazer o trabalho? Duvido que, por exemplo, tamponar cada novo ponto seja mais eficiente
  • Transforme a classe de recurso em uma matriz NumPy. Isso ajudaria? Até agora, não trabalhei muito com o NumPy e não gostaria de me aprofundar, a menos que alguém me diga que isso pode realmente ajudar a reduzir o tempo de processamento
  • Algo mais?

Qual versão do Arcmap você está usando?
Martin

Você já considerou o PostGIS? Isso é uma opção?
Chad Cooper

Lamento que eu esqueci isso: ArcGIS 10.1 // Python 2.7
Stéphane Henriod

Não, infelizmente, o PostGIS não é uma opção, minhas mãos estão muito atadas aqui ... Na melhor das hipóteses, posso usar o Oracle com as funções SDE
Stéphane Henriod

Respostas:


13

E se você alimentasse os pontos em uma matriz numpy e usasse um cKDTree discreto para procurar vizinhos. Eu processo nuvens de pontos LiDAR com um grande número de pontos (> 20 milhões) em vários MINUTES usando essa técnica. Há documentação aqui para o kdtree e aqui para conversão numpy. Basicamente, você lê x, y em uma matriz e itera sobre cada ponto da matriz, encontrando índices de pontos a uma certa distância (vizinhança) de cada ponto. Você pode usar esses índices para calcular outros atributos.


esta resposta é melhor do que a minha
radouxju

Gosto dessa ideia, mas não tenho nenhum problema na estação de trabalho em que estou trabalhando (e nenhum direito de administrador). Se eu conseguir instalar este pacote, tentarei #
Stéphane Henriod

4

Estou com Barbarossa ... os cursores do arco-íris são insanamente mancos, então eu os uso apenas para atravessar uma mesa ou aula de recurso exatamente uma vez. Se não consigo concluir o trabalho em um ciclo, uso o cursor para preencher outro tipo de estrutura de dados e trabalhar com isso.

Se você não quer se incomodar com o numpy, basta criar um dicionário python simples em que você use suas coordenadas como uma chave de texto simples e preencha os atributos necessários para o cálculo em uma lista como o valor do item do dicionário.

Em uma segunda etapa, você pode facilmente obter os valores necessários para calcular um ponto, simplesmente obtendo-os do seu dicionário (o que é incrivelmente rápido, devido ao índice de itens dos dicionários).


Na verdade, gosto da sua ideia com dicionários e acabei de implementá-la. Realmente funciona muito melhor ... até que eu escreva os resultados com uma linha.insertRow () ... Alguma idéia de como posso melhorar essa parte também?
Stéphane Henriod

Eu tive um problema semelhante em que tive que selecionar cerca de 10.000 pontos dos 14 milhões. e exclua-o. arcpy.cursors onde somente é possível excluir cerca de 1 ou 2 pontos por segundo (!). então instalei o módulo pyodbc para excluí-los com uma única instrução SQL DELETE em apenas um segundo. ATUALIZAR sobre SQL trará muitas melhorias, desde que você queira modificar atributos ... no entanto, você precisará instalar módulos python adicionais ... mas vale a pena.
Jürgen Zornig

2

Para uma grade regular, deve ser muito mais eficiente trabalhar em um formato raster. Converta sua primeira grade em uma varredura, para poder reamostrar na mesma resolução usando um interpolador bilinear, mas deslocando sua imagem de saída em 1/2 pixel em X e Y e retornando novamente aos pontos, se você ainda precisar de pontos.

EDIT: para regras de decisões complexas, você pode converter cada um dos campos necessários como uma nova banda de varredura, fazer quatro cópias dessas bandas e mudar sua varredura nas 4 direções por 1/2 pixel (+50, - 50), (+ 50, + 50), (-50, -50) e (-50, + 50). Então você pode usar álgebra de mapa regular


Obrigado, na verdade, pensei nessa solução, mas não tenho certeza se / como posso implementar o cálculo do novo valor se estiver no formato raster. Deixe-me explicar: para cada novo ponto (ou nova célula raster), preciso calcular seu valor como tal: pego o valor de cada um de seus vizinhos. Cada um desses valores tem uma probabilidade de atribuir um valor específico ao novo ponto. Por exemplo, se um vizinho tiver o valor 202, ele fornecerá o valor 3 (com um peso de 1) ou o valor 11 (com um peso de 5). Em seguida, soma-se para todos os 4 vizinhos e encontrar o novo valor ... Não tenho certeza se isso é muito claro ...
Stéphane Henriod

PS: o cálculo para encontrar o novo valor pode, em alguns casos, basear-se em 2 atributos, não apenas em um, que pode descartar a abordagem Raster
Stéphane Henriod

para sua soma ponderada, você só precisa de duas barras de rastreio: uma onde você resample o produto dos pesos e valores, e a segunda onde você resample somente os pesos. Se você dividir o primeiro pelo segundo, obtém sua soma ponderada.
precisa saber é o seguinte

1
@ StéphaneHenriod - como sugestão, considere editar a pergunta para adicionar essas especificações adicionais. Dada a pergunta inicial, acho que essa resposta faz muito sentido, mas com essa nova informação, a resposta de Barbarossa parece boa.
Nicksan

2

Obrigado a todos por sua ajuda!

Finalmente encontrei uma maneira muito não-pitônica de resolver esse problema ... O que estava demorando mais tempo computacional era encontrar os quatro vizinhos de cada ponto. Em vez de usar os atributos X e Y (com um cursor arcpy ou dentro de outra estrutura de dados, como um ditionary python), acabei usando a ferramenta ArcGIS Generate near table . Suponho que isso aproveite os índices espaciais e os desempenhos são obviamente muito mais altos, sem que eu precise implementar o índice pessoalmente.


0

O problema com os cursores é que você pode percorrê-los de uma maneira apenas e não pode voltar. Embora não seja recomendado, você pode preencher os feautres em uma estrutura se estiver planejando revisá-los.

Se você conseguiu processar seus recursos em um único loop, sugiro ativar a reciclagem. É um parâmetro na função da classe de recurso de pesquisa que permite ao python reutilizar a memória alocada por recursos antigos e tornar mais rápido o deslocamento dos recursos em um cursor. Você pode processar sua grade 80% mais rápido.

O problema é que você não pode ativar a reciclagem se estiver planejando armazenar recursos recuperados de um cursor.


Quero explorar esse assunto "recicle cursor", mas não consigo encontrar nenhuma documentação na Ajuda da ESRI. Você tem um link? O Cursor de Pesquisa não possui um parâmetro de reciclagem. Select_by_Attribute não possui esse parâmetro. Não vejo nada em ENV.
klewis


1
Eu não acho que "reutilizar cursores" esteja disponível no ArcPy, apenas nos Arcobjects principais.
klewis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.