Rationalisation du code Python pour le Big Data

34

J'ai du code Python conçu pour traiter les fichiers de formes ponctuels via le flux de travail suivant:

  1. Fusionner des points
  2. Intégrez des points, de sorte que tous les points situés à moins de 1 m l'un de l'autre deviennent un point
  3. Créer une couche d'entités, où les points avec z <10 sont sélectionnés
  4. Points tampons
  5. Résolution de polygone à raster de 1 m
  6. Reclassifier, où 1 - 9 = 1; NoData = 0

Chaque fichier de formes contient environ 250 000 à 350 000 points couvrant environ 5 x 7 km. Les données de points utilisées comme entrées représentent les emplacements des arbres. Chaque point (c'est-à-dire un arbre) est associé à une valeur "z" qui représente le rayon de la couronne et est utilisée dans le processus de mise en mémoire tampon. Mon intention est d'utiliser la sortie binaire finale dans un processus séparé pour produire un raster décrivant la couverture de la canopée.

J'ai fait un test avec quatre fichiers de formes et cela a produit une trame de 700 Mo et a pris 35 minutes (processeur i5 et 8 Go de RAM). Étant donné que je devrai exécuter ce processus sur 3500 shapefiles, je vous serais reconnaissant de tout conseil pour rationaliser le processus (voir le code ci-joint). De manière générale, quel est le meilleur moyen de gérer le Big Data avec le géotraitement? Plus précisément, y a-t-il des modifications à apporter au code ou au flux de travail qui pourraient aider à accroître l'efficacité?

modifier :

Temps (% du total) pour les tâches de géotraitement:

  • Fusion = 7,6%
  • Intégrer = 7.1%
  • Fonction à Lyr = 0
  • Tampon = 8,8%
  • Poly à raster = 74,8%
  • Reclassifier = 1.6%

entrez la description de l'image ici

# 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
la source
3
Il peut être intéressant de définir un code de chronométrage des performances afin de déterminer si la plus grande partie du temps est consacrée à une ou plusieurs étapes, de manière à ce que vous puissiez vous concentrer sur les améliorations de performances
PolyGeo
5
Je ne pense pas que vous ayez beaucoup d'options pour améliorer les performances si vous continuez à utiliser ArcPy. Peut-être que vous pouvez regarder d'autres outils pour faire ceci? Des outils comme FME ou peut-être des postgis?
tmske
3
Le type de pixel utilisé n'est pas clair, mais s'il s'agit d'un octet (comme il se doit), le stockage de données brutes serait de 5000x7000 = 35 Mo (~ 33,4 Mo) par raster, ce qui n'est pas si énorme. Cependant, la prochaine dimension de 3500 (dimension temporelle?) Augmente la taille brute totale à ~ 114 Go.
Mike T
5
Bien que je ne puisse pas dire de cette description ce que fait ou fait l’algorithme, dans la plupart des cas, les tampons de points suivis d’une pixellisation devraient être remplacés par une pixellisation des points suivie d’une statistique focale (généralement une moyenne ou une somme). Le résultat sera le même mais, en évitant les longues étapes de mise en mémoire tampon et de polyprastérisation, il sera obtenu beaucoup plus rapidement. Je pense (fortement) que des accélérations supplémentaires substantielles pourraient être obtenues, mais je ne peux pas fournir de conseils spécifiques en raison de l'imprécision de la description de la procédure.
whuber
2
Les tampons autour des points ont une taille variable (basée sur la valeur z du point). Je pense que, tout en conservant les statistiques focales, vous devez scinder les points de résultat par valeur z et créer des statistiques raster et focales sur chaque ensemble (en utilisant z comme rayon sur un voisinage circulaire avec un maximum comme statistique). Ensuite, exécutez Statistiques de cellule sur les 9 rasters avec la statistique max afin de combiner les résultats. (Ce qui est probablement encore beaucoup plus rapide que buffer et rastérisé avec un gros jeu de données.)
blord-castillo

Réponses:

10

Certains changements d'algorithmes devraient vous aider.

Exécutez votre sélection avant la fusion ou l'intégration. Cela réduira considérablement les dernières fonctions les plus coûteuses.

La fusion et l'intégration coûtent cher en mémoire. Vous souhaitez donc continuer à éliminer les fonctionnalités lorsque vous importez des classes d'entités, et essayez d'effectuer vos fusions dans un arbre binaire pour limiter la taille des fusions et des intégrations. par exemple, pour quatre fichiers de formes, vous fusionnez deux fichiers de formes et les intégrez; fusionner deux autres fichiers de formes et les intégrer; fusionner les deux classes d'entités résultantes et les intégrer.

Votre file d'attente commence par une file de références de fichier de formes. Vous avez également une file d'attente de résultats dans laquelle placer les résultats. La méthode run () pour votre agent de traitement parallèle effectue les opérations suivantes: Retirez deux éléments de la file d'attente. Si aucun élément n'est pris (la file d'attente est vide), arrêtez le travailleur. Si un élément est pris, placez-le directement dans la file d'attente des résultats.

Si deux éléments sont pris, pour chaque élément: s'il s'agit d'un fichier de formes, sélectionnez-le pour z <10 et créez une classe d'entités in_memory; sinon, il s'agit déjà d'une classe d'entités in_memory et ignore l'étape de sélection. Fusionnez les deux classes d'entités in_memory pour créer une nouvelle classe d'entités in_memory. Supprimer les deux classes d'entités d'origine. Exécuter intégrer sur la nouvelle classe d'entités. Placez cette classe d'entités dans la file d'attente des résultats.

Puis lancez une boucle while externe. La boucle commence par la file d'attente du fichier de formes et teste une longueur supérieure à 1. Elle exécute ensuite la file d'attente à travers les agents. Si la longueur de la file d'attente de résultats est supérieure à 1, la boucle while exécute un autre traitement parallèle exécuté par les agents jusqu'à ce que la file d'attente soit égale à 1 classe d'entités in_memory.

Par exemple, si vous démarrez avec 3500 fichiers de formes, votre première file d'attente contiendra 3500 tâches. La seconde aura 1750 emplois. 875, 438, 219, 110, 55, 28, 14, 7, 4, 2, 1. Votre gros goulot d'étranglement sera la mémoire. Si vous ne disposez pas de suffisamment de mémoire (et que vous manquerez de mémoire lors de la création de la première file d'attente de résultats si c'est le cas), modifiez votre algorithme pour fusionner plus de 2 classes d'entités à la fois, puis intégrez-le, ce qui réduira la taille de votre première file d'attente de résultats en échange d'un temps de traitement plus long. Vous pouvez éventuellement écrire des fichiers de sortie et ignorer l'utilisation de classes d'entités in_memory. Cela vous ralentira considérablement, mais vous évitera le goulot d'étranglement de la mémoire.

Ce n'est qu'après avoir fusionné et intégré tous les fichiers de formes, en se terminant par une seule classe d'entités, que vous effectuez ensuite la mise en mémoire tampon, poly to raster et reclassification. De cette façon, ces trois opérations ne sont effectuées qu'une seule fois et vous gardez votre géométrie simple.

Blord-Castillo
la source
+1 pour utiliser l' espace de travail in_memory si vos données vont tenir dans la mémoire. Cela accélère considérablement les opérations de géotraitement.
RyanDalton
C'est du bon matos. Je pense que cela pourrait être encore mieux avec un diagramme et un psuedocode (ou un code réel!).
blah238
Oui, j'aimerais avoir du temps pour m'engager dans le code. De toute façon, je dois écrire un nouveau script de démonstration de traitement en parallèle.
blord-castillo
14

La première chose que je ferais serait de surveiller l'utilisation des ressources de votre système à l'aide de quelque chose comme Resource Monitor sous Windows 7 ou perfmon sous Vista / XP pour savoir si vous êtes lié au processeur , à la mémoire ou aux E / S. .

Si vous êtes lié à la mémoire ou aux entrées-sorties, vous ne pouvez probablement rien faire d'autre que mettre à niveau le matériel, réduire la taille du problème ou modifier complètement l'approche.

Si vous déterminez que vous êtes lié au processeur, j'expérimenterais le multiprocessingmodule ou l'un des nombreux autres packages de traitement parallèle basés sur Python. disponibles, pour voir si vous pouvez utiliser davantage de cœurs de processeur pour accélérer vos opérations.

Le truc pour le multitraitement et le parallélisme en général consiste à trouver un bon schéma de partitionnement qui:

  1. Vous permet de diviser les entrées en ensembles de travail plus petits, puis de recombiner les résultats d'une manière qui a du sens,
  2. Ajoute le moins de temps système (certains sont inévitables par rapport au traitement en série), et
  3. Vous permet d'ajuster la taille de l'ensemble de travail afin d'utiliser au mieux les ressources du système pour des performances optimales.

Vous pouvez utiliser le script que j'ai créé dans cette réponse comme point de départ: Portage du code Avenue pour Produire des ombres construites dans ArcPy / Python pour ArcGIS Desktop?

Voir également ce billet de blog ESRI Geoprocessing sur le sujet: Multiprocessing Python - Approches et considérations

Je pense que votre cas va être encore plus difficile en raison de la nature plus "boîte noire" des outils que vous utilisez, plutôt que des tableaux de géométrie à grain plus fin avec lesquels je travaillais. Peut-être que travailler avec des tableaux NumPy peut être utile.

Je suis également tombé sur du matériel de lecture intéressant si vous vouliez aller au-delà de arcpy:

blah238
la source