Simplificando o código Python para Big Data

34

Eu tenho um código Python que foi projetado para levar shapefiles de ponto através do seguinte fluxo de trabalho:

  1. Mesclar pontos
  2. Integre pontos, de modo que quaisquer pontos a menos de 1 m um do outro se tornem um ponto
  3. Camada Criar recurso, onde pontos com z <10 são selecionados
  4. Pontos de buffer
  5. Resolução de polígono para varredura de 1m
  6. Reclassifique, onde 1 - 9 = 1; NoData = 0

Cada arquivo de forma tem aproximadamente 250.000 a 350.000 pontos, cobrindo ~ 5x7 km. Os dados dos pontos usados ​​como entradas representam os locais da árvore. Cada ponto (isto é, árvore) tem um valor "z" associado que representa o raio da coroa e é usado no processo de buffer. Minha intenção é usar a saída binária final em um processo separado para produzir uma varredura que descreve a cobertura do dossel.

Fiz um teste com quatro shapefiles e ele produziu um raster de 700 MB e levou 35 minutos (processador i5 e 8 GB de RAM). Visto que precisarei executar esse processo em 3500 shapefiles, agradeceria qualquer conselho para simplificar o processo (consulte o código em anexo). De um modo geral, qual é a melhor maneira de lidar com o geoprocessamento de big data? Mais especificamente, existem ajustes no código ou no fluxo de trabalho que podem ajudar a aumentar a eficiência?

Editar :

Tempo (% do total) para tarefas de geoprocessamento:

  • Mesclar = 7,6%
  • Integrar = 7,1%
  • Recurso para Lyr = 0
  • Tampão = 8,8%
  • Poli para Raster = 74,8%
  • Reclassificar = 1,6%

insira a descrição da imagem aqui

# Import arcpy module
import arcpy

# Check out any necessary licenses
arcpy.CheckOutExtension("spatial")

# Script arguments
temp4 = arcpy.GetParameterAsText(0)
if temp4 == '#' or not temp4:
    temp4 = "C:\\gdrive\\temp\\temp4" # provide a default value if unspecified

Reclassification = arcpy.GetParameterAsText(1)
if Reclassification == '#' or not Reclassification:
    Reclassification = "1 9 1;NODATA 0" # provide a default value if unspecified

Multiple_Value = arcpy.GetParameterAsText(2)
if Multiple_Value == '#' or not Multiple_Value:
    Multiple_Value = "C:\\t1.shp;C:\\t2.shp;C:\\t3.shp;C:\\t4.shp" # provide a default value if unspecified

# Local variables:
temp_shp = Multiple_Value
Output_Features = temp_shp
temp2_Layer = Output_Features
temp_Buffer = temp2_Layer
temp3 = temp_Buffer

# Process: Merge
arcpy.Merge_management(Multiple_Value, temp_shp, "x \"x\" true true false 19 Double 0 0 ,First,#,C:\\#########omitted to save space

# Process: Integrate
arcpy.Integrate_management("C:\\gdrive\\temp\\temp.shp #", "1 Meters")

# Process: Make Feature Layer
arcpy.MakeFeatureLayer_management(temp_shp, temp2_Layer, "z <10", "", "x x VISIBLE NONE;y y VISIBLE NONE;z z VISIBLE NONE;Buffer Buffer VISIBLE NONE")

# Process: Buffer
arcpy.Buffer_analysis(temp2_Layer, temp_Buffer, "z", "FULL", "ROUND", "NONE", "")

# Process: Polygon to Raster
arcpy.PolygonToRaster_conversion(temp_Buffer, "BUFF_DIST", temp3, "CELL_CENTER", "NONE", "1")

# Process: Reclassify
arcpy.gp.Reclassify_sa(temp3, "Value", Reclassification, temp4, "DATA")
Aaron
fonte
3
Pode valer a pena colocar em algum código de tempo de desempenho para estabelecer se a maior parte do tempo está sendo
executada
5
Eu não acho que você tenha muitas opções para melhorar o desempenho se continuar usando o ArcPy. Talvez você possa procurar outras ferramentas para fazer isso? Ferramentas como FME ou talvez postgis?
tmske
3
Não está claro que tipo de pixel está sendo usado, mas se for "Byte" (o que deveria ser), o armazenamento de dados brutos seria 5000x7000 = 35Mb (~ 33,4MB) por raster, o que na verdade não é tão grande. No entanto, a próxima dimensão de 3500 (dimensão do tempo?) Aumenta o tamanho total bruto para ~ 114 GB.
Mike T
5
Embora eu não possa dizer a partir dessa descrição o que o algoritmo está fazendo (ou pretende fazer), na maioria dos casos, os buffers de pontos seguidos de rasterização devem ser substituídos pela rasterização dos pontos seguida por uma estatística focal (geralmente uma média ou soma). O resultado será o mesmo, mas, evitando as longas etapas de buffer e poli rasterização, será obtido muito mais rapidamente. Eu (fortemente) suspeito que acelerações adicionais substanciais poderiam ser obtidas, mas não posso fornecer conselhos específicos devido à imprecisão da descrição do procedimento.
whuber
2
Os buffers ao redor dos pontos são de tamanho variável (com base no valor z do ponto). Se você ainda faz estatísticas focais, é necessário dividir os pontos do resultado pelo valor z e fazer estatísticas raster e focais em cada conjunto (usando z como o raio em uma vizinhança circular com o máximo como o stat). Em seguida, execute as Estatísticas das células em todas as 9 rasters com o status máximo para combinar os resultados. (Que ainda é, provavelmente, muito mais rápido do buffer e rasterize com um grande conjunto de dados.)
blord-castillo

Respostas:

10

Algumas alterações no algoritmo que devem ajudá-lo.

Execute sua seleção primeiro antes da mesclagem ou integração. Isso reduzirá significativamente as funções posteriores que são mais caras.

Mesclar e integrar são caros em memória, portanto, você deseja continuar eliminando recursos à medida que cria classes de recursos e tenta fazer suas mesclagens em uma árvore binária para manter o tamanho das mesclagens e integrações baixas. por exemplo, para quatro shapefiles, você mescla dois shapefiles e os integra; mesclar mais dois shapefiles e integrar; mesclar as duas classes de recursos resultantes e integrar.

Sua fila de tarefas é iniciada como uma fila de referências de shapefile. Você também tem uma fila de resultados para inserir os resultados. O método run () para o seu trabalhador de processamento paralelo fará essas operações: Retire dois itens da fila. Se nenhum item for utilizado (a fila está vazia), encerre o trabalhador. Se um item for obtido, coloque-o diretamente na fila de resultados.

Se dois itens forem utilizados, para cada item: se for um shapefile, selecione z <10 e crie uma classe de recurso in_memory; caso contrário, já é uma classe de recurso in_memory e pula a etapa de seleção. Mesclar as duas classes de recurso in_memory para criar uma nova classe de recurso in_memory. Exclua as duas classes de recurso originais. Execute a integração na nova classe de recurso. Coloque essa classe de recurso na fila de resultados.

Em seguida, execute um loop while externo. O loop começa com a fila shapefile e testa um comprimento maior que 1. Em seguida, executa a fila pelos trabalhadores. Se a fila de resultados tiver um comprimento maior que 1, o loop while executará outro processamento paralelo executado pelos trabalhadores até que a fila de resultados seja 1 classe de recurso in_memory.

Por exemplo, se você começar com 3500 shapefiles, sua primeira fila terá 3500 trabalhos. O segundo terá 1750 empregos. 875, 438, 219, 110, 55, 28, 14, 7, 4, 2, 1. Seu grande gargalo será a memória. Se você não tiver memória suficiente (e ficará sem memória na criação da primeira fila de resultados, se for esse o caso), modifique seu algoritmo para mesclar mais de duas classes de recursos ao mesmo tempo e depois integrar, o que reduzirá o tamanho da sua primeira fila de resultados em troca de um tempo de processamento maior. Opcionalmente, você pode gravar arquivos de saída e pular usando as classes de recurso in_memory. Isso diminuirá consideravelmente a velocidade, mas superaria o gargalo da memória.

Somente após executar a mesclagem e integração em todos os arquivos de forma, terminando com uma única classe de recurso, você executa o buffer, poli para rasterizar e reclassificar. Dessa forma, essas três operações são executadas apenas uma vez e você mantém sua geometria simples.

blord-castillo
fonte
+1 para usar o espaço de trabalho in_memory se seus dados caberem na memória. Acelera significativamente as operações de geoprocessamento.
precisa saber é o seguinte
Isso é bom. Eu acho que poderia ser ainda melhor com um diagrama e algum psuedocode (ou código real!).
blah238
Sim, eu gostaria de ter algum tempo para me comprometer com o código. Eu preciso escrever um novo script de demonstração de processamento paralelo de qualquer maneira.
Blord-castillo 10/08/2012
14

A primeira coisa que eu faria é monitorar a utilização de recursos do seu sistema usando algo como o Monitor de Recursos no Windows 7 ou executar o Vista / XP para ter uma idéia de se você está vinculado à CPU -, memória - ou IO .

Se você tem memória ou IO, provavelmente há muito pouco a fazer, além de atualizar o hardware, reduzir o tamanho do problema ou alterar completamente a abordagem.

Se você determinar que está vinculado à CPU, eu experimentaria o multiprocessingmódulo ou um dos muitos outros pacotes de processamento paralelo baseados em Python disponíveis para verificar se você pode usar mais núcleos de CPU para acelerar suas operações.

O truque para o multiprocessamento e o paralelismo em geral é encontrar um bom esquema de particionamento que:

  1. Permite dividir as entradas em conjuntos de trabalho menores e recombinar os resultados de uma maneira que faça sentido,
  2. Adiciona a menor quantidade de sobrecarga (alguns são inevitáveis ​​em comparação com o processamento em série) e
  3. Permite ajustar o tamanho do conjunto de trabalho para melhor utilizar os recursos do sistema para otimizar o desempenho.

Você pode usar o script que criei nesta resposta como ponto de partida: Código da Porting Avenue para produzir sombras de construção no ArcPy / Python para ArcGIS Desktop?

Veja também esta postagem no blog da ESRI Geoprocessing sobre o assunto: Multiprocessamento Python - Abordagens e considerações

Eu acho que o seu caso será ainda mais desafiador devido à natureza mais "caixa preta" das ferramentas que você está usando, em vez das matrizes de geometria mais refinadas com as quais eu estava trabalhando. Talvez trabalhando com NumPy matrizes possa ser útil.

Também encontrei algum material de leitura interessante, se você quisesse ir além do arcpy:

blah238
fonte