Comment améliorer les performances lors de l'utilisation de curseurs ArcGIS en Python avec de grandes tables?

10

J'ai une classe d'entités ponctuelles assez importante dans une géodatabase fichier (~ 4 000 000 d'enregistrements). Il s'agit d'une grille de points régulière avec une résolution de 100 m.

J'ai besoin d'effectuer une sorte de généralisation sur cette couche. Pour cela, je crée une nouvelle grille où chaque point se situe au milieu de 4 "anciens" points:

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

[*] = point de la grille d'origine - [o] = point de la nouvelle grille

La valeur d'attribut de chaque nouveau point est calculée sur la base des valeurs pondérées de ses 4 voisins dans l'ancienne grille. Je boucle donc sur tous les points de ma nouvelle grille et, pour chacun d'eux, je boucle sur tous les points de mon ancienne grille, afin de trouver les voisins (en comparant les valeurs de X et Y dans la table attributaire). Une fois que 4 voisins ont été trouvés, nous sortons de la boucle.

Il n'y a pas de complexité méthodologique ici mais mon problème est que, sur la base de mes premiers tests, ce script va durer des semaines ...

Voyez-vous une possibilité de le rendre plus efficace? Quelques idées sur le dessus de ma tête:

  • Indexez les champs X et Y => Je l'ai fait mais je n'ai pas remarqué de changement de performance significatif
  • Effectuez une requête spatiale pour trouver les voisins plutôt que basée sur un attribut. Cela aiderait-il réellement? Quelle fonction spatiale dans ArcGIS devrait faire le travail? Je doute que, par exemple, la mise en mémoire tampon de chaque nouveau point se révélera plus efficace
  • Transformez la classe d'entités en tableau NumPy. Est-ce que cela aiderait? Je n'ai pas beaucoup travaillé avec NumPy jusqu'à présent et je ne voudrais pas m'y plonger à moins que quelqu'un ne me dise que cela pourrait vraiment aider à réduire le temps de traitement
  • Rien d'autre?
Stéphane Henriod
la source
Quelle version d'Arcmap utilisez-vous?
Martin
Avez-vous pensé à PostGIS? Est-ce une option?
Chad Cooper
Désolé d'avoir oublié cela: ArcGIS 10.1 // Python 2.7
Stéphane Henriod
Non, PostGIS n'est malheureusement pas une option, mes mains sont malheureusement assez liées ici ... Au mieux je peux utiliser Oracle avec les fonctions SDE
Stéphane Henriod

Réponses:

13

Et si vous introduisiez les points dans un tableau numpy et utilisiez un cKDTree scipy pour rechercher des voisins. Je traite des nuages ​​de points LiDAR avec un grand nombre de points (> 20 millions) en plusieurs MINUTES en utilisant cette technique. Il y a de la documentation ici pour kdtree et ici pour la conversion numpy. Fondamentalement, vous lisez les x, y dans un tableau et parcourez chaque point du tableau en trouvant des indices de points à une certaine distance (voisinage) de chaque point. Vous pouvez utiliser ces indices pour calculer ensuite d'autres attributs.

Barbarossa
la source
cette réponse est meilleure que la mienne
radouxju
J'aime cette idée mais je n'ai pas de scipy sur le poste de travail sur lequel je travaille (et pas de droits d'administrateur). Si j'arrive à faire installer ce paquet, alors je vais l'essayer
Stéphane Henriod
4

Je suis avec Barbarossa ... les curseurs arcpy sont incroyablement boiteux, donc je ne les utilise que pour parcourir une table ou une classe d'entités exactement une fois. Si je ne peux pas faire le travail en un seul cycle, j'utilise le curseur pour remplir un autre type de structure de données et travailler avec cela.

Si vous ne voulez pas vous soucier de numpy, créez simplement un dictionnaire python simple où vous utilisez vos coordonnées comme une simple clé de texte et remplissez les attributs dont vous avez besoin pour le calcul dans une liste en tant que valeur de l'élément de dictionnaire.

Dans une deuxième étape, vous pouvez facilement obtenir les valeurs dont vous avez besoin pour calculer un point en les obtenant simplement à partir de votre dictionnaire (ce qui est incroyablement rapide, en raison de l'inexistence des dictionnaires dans les éléments).

Jürgen Zornig
la source
J'aime vraiment votre idée avec les dictionnaires et je viens de l'implémenter. Cela fonctionne en effet beaucoup mieux ... jusqu'à ce que j'écrive réellement les résultats avec une ligne.insertRow () ... Une idée de la façon dont je peux améliorer cette partie également?
Stéphane Henriod
J'ai eu un problème similaire où j'ai dû sélectionner quelque 10 000 points sur 14 Mio. puis supprimez-le. arcpy.cursors où seulement capable de supprimer environ 1 ou 2 points par seconde (!). J'ai donc installé le module pyodbc pour les supprimer avec une seule instruction SQL DELETE en une seconde seulement. MISE À JOUR sur SQL vous apportera beaucoup d'amélioration, tant que vous ne souhaitez modifier que les attributs ... néanmoins vous devrez installer des modules python supplémentaires ... mais ça vaut le coup.
Jürgen Zornig
2

Pour une grille régulière, il devrait être de loin plus efficace de travailler dans un format raster. Convertissez votre première grille en un raster, vous pouvez rééchantillonner à la même résolution en utilisant un interpolateur bilinéaire mais en décalant votre image de sortie de 1/2 pixel en X et Y, et de nouveau en points si vous avez encore besoin de points.

EDIT: pour les règles de décisions complexes, vous pouvez convertir chacun des champs dont vous avez besoin en une nouvelle bande raster, puis vous faites quatre copies de ces bandes et vous décalez votre raster dans les 4 directions de 1/2 pixel (+50, - 50), (+ 50, + 50), (-50, -50) et (-50, + 50). Ensuite, vous pouvez utiliser l'algèbre de carte régulière

radouxju
la source
Merci, j'ai pensé à cette solution mais je ne suis pas sûr si / comment je peux implémenter le calcul de la nouvelle valeur si au format raster. Je m'explique: pour chaque nouveau point (ou nouvelle cellule raster) j'ai besoin de calculer sa valeur comme telle: je prends la valeur de chacun de ses voisins. Chacune de ces valeurs a une probabilité de donner une valeur particulière au nouveau point. Par exemple, si un voisin a la valeur 202, alors il donnera la valeur 3 (avec un poids de 1) ou la valeur 11 (avec un poids de 5). Nous résumons ensuite pour les 4 voisins et trouvons la nouvelle valeur ... Je ne sais pas si c'est très clair ...
Stéphane Henriod
PS: le calcul pour trouver la nouvelle valeur peut, dans certains cas, être basé sur 2 attributs, pas un seul, qui pourraient écarter l'approche Raster
Stéphane Henriod
pour votre somme pondérée, vous avez juste besoin de deux rasters: l'un où vous rééchantillonnez le produit des poids et des valeurs, le second où vous rééchantillonnez uniquement les poids. Si vous divisez le premier par le second, vous obtenez votre somme pondérée.
radouxju
1
@ StéphaneHenriod - à titre de suggestion, vous pourriez envisager de modifier la question pour ajouter ces spécifications supplémentaires. Compte tenu de la question initiale, je pense que cette réponse a beaucoup de sens, mais avec ces nouvelles informations, la réponse de Barbarossa semble bonne.
nicksan
2

Merci à tous pour votre aide!

J'ai finalement trouvé un moyen très non-pythonique pour résoudre ce problème ... Ce qui prenait en fait le plus de temps de calcul était de trouver les 4 voisins de chaque point. Plutôt que d'utiliser les attributs X et Y (soit avec un curseur arcpy, soit dans une autre structure de données, comme un ditionnaire python), j'ai fini par utiliser l'outil ArcGIS Generate near table . Je suppose que cela profite des index spatiaux et les performances sont évidemment beaucoup plus élevées, sans que je doive implémenter l'index moi-même.

Stéphane Henriod
la source
0

Le problème avec les curseurs est que vous ne pouvez les parcourir que d'une seule manière et que vous ne pouvez pas revenir en arrière. Bien que cela ne soit pas recommandé, vous pouvez remplir les feautres dans une structure si vous prévoyez de les revoir.

Si vous pouviez traiter vos fonctionnalités en une seule boucle, je vous suggère d'activer le recyclage. C'est un paramètre de votre fonction de recherche de fonctionnalités qui permet à python de réutiliser la mémoire allouée par les anciennes fonctionnalités et de rendre la traversée des fonctionnalités dans un curseur beaucoup plus rapide. Vous pouvez traiter votre grille 80% plus rapidement.

Le problème est que vous ne pouvez pas activer le recyclage si vous envisagez de stocker les fonctionnalités récupérées à partir d'un curseur.

hnasr
la source
Je souhaite explorer ce sujet "curseur de recyclage" mais je ne trouve aucune documentation sur l'aide d'ESRI. avez vous un lien? Le curseur de recherche n'a pas de paramètre de recyclage. Select_by_Attribute n'a pas un tel paramètre. Je ne vois rien dans ENV.
klewis
J'ai écrit un article il y a quelque temps husseinnasser.com/2009/08/when-to-use-recycling-cursor.html?m=1
hnasr
1
Je ne pense pas que la "réutilisation des curseurs" soit disponible via ArcPy, uniquement avec les principaux Arcobjects.
klewis