Jak poprawić wydajność podczas używania kursorów ArcGIS w Pythonie z dużymi tabelami?

10

Mam dość dużą klasę obiektów punktowych w geobazie pliku (~ 4 000 000 rekordów). Jest to regularna siatka punktów o rozdzielczości 100 m.

Muszę wykonać rodzaj uogólnienia na tej warstwie. W tym celu tworzę nową siatkę, w której każdy punkt znajduje się w środku 4 „starych” punktów:

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

[*] = punkt oryginalnej siatki - [o] = punkt nowej siatki

Wartość atrybutu każdego nowego punktu jest obliczana na podstawie ważonych wartości 4 sąsiadów w starej siatce. Zapętlam więc wszystkie punkty mojej nowej siatki i dla każdego z nich zapętlam wszystkie punkty mojej starej siatki, aby znaleźć sąsiadów (porównując wartości X i Y w tabeli atrybutów). Po znalezieniu 4 sąsiadów wychodzimy z pętli.

Nie ma tu złożoności metodologicznej, ale moim problemem jest to, że na podstawie moich pierwszych testów skrypt ten będzie trwał kilka tygodni, aby ukończyć ...

Czy widzisz jakąś możliwość zwiększenia wydajności? Kilka pomysłów na czubku głowy:

  • Zindeksuj pola X i Y => Zrobiłem to, ale nie zauważyłem żadnej znaczącej zmiany wydajności
  • Wykonaj zapytanie przestrzenne, aby znaleźć sąsiadów, a nie oparte na atrybutach. Czy to naprawdę pomogłoby? Jaka funkcja przestrzenna w ArcGIS powinna działać? Wątpię, aby np. Buforowanie każdego nowego punktu okazało się bardziej wydajne
  • Przekształć klasę obiektów w tablicę NumPy. Czy to pomogłoby? Do tej pory nie pracowałem dużo z NumPy i nie chciałbym się w to zanurzyć, chyba że ktoś mi powie, że może to naprawdę pomóc w skróceniu czasu przetwarzania
  • Coś jeszcze?
Stéphane Henriod
źródło
Jakiej wersji Arcmap używasz?
Martin
Czy rozważałeś PostGIS? Czy to jest opcja?
Chad Cooper
Przepraszam, że zapomniałem: ArcGIS 10.1 // Python 2.7
Stéphane Henriod
Nie, PostGIS nie jest niestety opcją, niestety mam tutaj dość związane ręce ... W najlepszym wypadku mogę używać Oracle z funkcjami SDE
Stéphane Henriod

Odpowiedzi:

13

Co jeśli nakarmisz punkty tablicą liczb liczbowych i użyjesz zwięzłego cKDTree do szukania sąsiadów. Przetwarzam chmury punktów LiDAR z dużą liczbą punktów (> 20 milionów) w kilka MINUT za pomocą tej techniki. Jest dokumentacja tutaj dla kdtree i tutaj dla numpy nawrócenia. Zasadniczo odczytujesz x, y do tablicy i iterujesz po każdym punkcie tablicy, znajdując wskaźniki punktów w pewnej odległości (sąsiedztwie) każdego punktu. Możesz użyć tych wskaźników, aby następnie obliczyć inne atrybuty.

Barbarossa
źródło
ta odpowiedź jest lepsza niż moja
radouxju
Podoba mi się ten pomysł, ale nie mam wprawdzie kiepskiej pracy na stacji roboczej, na której pracuję (i nie mam uprawnień administratora). Jeśli uda mi się zainstalować ten pakiet, spróbuję
Stéphane Henriod
4

Jestem z Barbarossą ... arkadowe kursory są niesamowicie kulawe, więc używam ich tylko do przemierzania tabeli lub klasy obiektów dokładnie raz. Jeśli nie mogę wykonać pracy w jednym cyklu, używam kursora, aby wypełnić inną strukturę danych i pracuję z tym.

Jeśli nie chcesz mieć kłopotów z numpy, po prostu stwórz prosty słownik python, w którym używasz swoich współrzędnych jako prostego klucza tekstowego i wypełnij atrybuty potrzebne do obliczeń na liście jako wartość elementu słownika.

W drugim kroku możesz łatwo uzyskać wartości potrzebne do obliczenia punktu, po prostu pobierając je ze słownika (który jest niesamowicie szybki, ze względu na hashindeks słowników pozycji).

Jürgen Zornig
źródło
Właściwie podoba mi się twój pomysł ze słownikami i właśnie go zrealizowałem. Rzeczywiście działa znacznie lepiej ... dopóki nie napiszę wyników za pomocą row.insertRow () ... Wiesz, jak mogę poprawić tę część?
Stéphane Henriod
Miałem podobny problem, w którym musiałem wybrać jakieś 10 000 punktów z 14 milionów. a następnie usuń go. arcpy.cursors, w których można usunąć tylko około 1 lub 2 punkty na sekundę (!). więc zainstalowałem moduł pyodbc, aby usunąć je za pomocą pojedynczej instrukcji SQL DELETE w ciągu zaledwie jednej sekundy. AKTUALIZACJA przez SQL przyniesie wiele ulepszeń, o ile chcesz tylko modyfikować atrybuty ... ale będziesz musiał zainstalować dodatkowe moduły python ... ale warto.
Jürgen Zornig
2

W przypadku zwykłej siatki praca w formacie rastrowym powinna być zdecydowanie bardziej wydajna. Przekształć pierwszą siatkę w raster, możesz ponownie próbkować w tej samej rozdzielczości za pomocą interpolatora dwuliniowego, ale przesuwając obraz wyjściowy o 1/2 piksela w X i Y, i ponownie z powrotem do punktów, jeśli nadal potrzebujesz punktów.

EDYCJA: w przypadku złożonych reguł decyzyjnych możesz przekonwertować każde z pól, które potrzebujesz jako nowe pasmo rastrowe, następnie tworzysz cztery kopie tych pasm i przesuwasz raster w 4 kierunkach o 1/2 piksela (+50, - 50), (+ 50, + 50), (-50, -50) i (-50, + 50). Następnie możesz użyć zwykłej algebry map

radouxju
źródło
Dzięki, właściwie pomyślałem o tym rozwiązaniu, ale nie jestem pewien, czy / jak mogę wdrożyć obliczenia nowej wartości w formacie rastrowym. Pozwól, że wyjaśnię: dla każdego nowego punktu (lub nowej komórki rastrowej) muszę obliczyć jego wartość jako taką: biorę wartość każdego z jej sąsiadów. Każda z tych wartości ma prawdopodobieństwo nadania określonej wartości nowemu punktowi. Na przykład, jeśli jeden sąsiad ma wartość 202, wówczas da wartość 3 (o wadze 1) lub wartość 11 (o wadze 5). Następnie podsumowujemy dla wszystkich 4 sąsiadów i znajdujemy nową wartość ... Nie jestem pewien, czy to jest bardzo jasne ...
Stéphane Henriod
PS: obliczenia w celu znalezienia nowej wartości mogą w niektórych przypadkach opierać się na 2 atrybutach, a nie tylko jednym, co może odrzucić podejście rastrowe
Stéphane Henriod
do sumy ważonej potrzebujesz tylko dwóch rastrów: jeden, w którym próbkujesz iloczyn wag i wartości, drugi, w którym próbkujesz tylko wag. Jeśli podzielisz pierwszą przez drugą, otrzymasz swoją ważoną sumę.
radouxju
1
@ StéphaneHenriod - jako sugestię warto rozważyć edycję pytania w celu dodania tych dodatkowych specyfikacji. Biorąc pod uwagę początkowe pytanie, myślę, że ta odpowiedź ma mnóstwo sensu, ale z tymi nowymi informacjami odpowiedź Barbarossy wygląda dobrze.
nicksan
2

Dziękujemy wszystkim za pomoc!

W końcu znalazłem bardzo nie-pytonowy sposób rozwiązania tego problemu ... To, co faktycznie zajmowało najwięcej czasu, to znalezienie 4 sąsiadów z każdego punktu. Zamiast używać atrybutów X i Y (z łukowatym kursorem lub w innej strukturze danych, takiej jak słownik python), skończyłem na użyciu narzędzia ArcGIS Generuj przy stole . Zakładam, że wykorzystuje to indeksy przestrzenne, a wydajność jest oczywiście znacznie wyższa, bez mojej implementacji indeksu.

Stéphane Henriod
źródło
0

Problem z kursorami polega na tym, że możesz je przełączać tylko w jeden sposób i nie możesz wrócić. Chociaż nie jest to zalecane, możesz wypełnić feautres w strukturze, jeśli planujesz je ponownie odwiedzić.

Jeśli udało Ci się przetworzyć swoje funkcje w jednej pętli, sugeruję włączenie recyklingu. Jest to parametr funkcji wyszukiwania funkcji klasy, który pozwala Pythonowi ponownie wykorzystać pamięć przydzieloną przez stare funkcje i znacznie przyspieszyć przeglądanie funkcji kursorem. Możesz przetwarzać swoją siatkę 80% szybciej.

Problem polega na tym, że nie można włączyć recyklingu, jeśli planujesz przechowywać odzyskane funkcje z kursorem.

hnasr
źródło
Chcę zapoznać się z tym tematem „kursor kosza”, ale nie mogę znaleźć żadnej dokumentacji w Pomocy ESRI. Czy masz link? Kursor wyszukiwania nie ma parametru kosza. Select_by_Attribute nie ma takiego parametru. Nic nie widzę w ENV.
klewis
Niedawno
hnasr
1
Nie sądzę, że „ponowne użycie kursorów” jest dostępne przez ArcPy, tylko z podstawowymi obiektami Arcobject.
klewis