To dość konceptualne pytanie, ale miałem nadzieję, że uda mi się uzyskać w tym zakresie kilka dobrych rad. Wiele programowania, które wykonuję, to tablice ( NumPy ); Często muszę dopasowywać elementy w co najmniej dwóch tablicach o różnych rozmiarach, a pierwszą rzeczą, do której się wybieram, jest pętla for lub, co gorsza, zagnieżdżona pętla for. Chcę jak najbardziej unikać pętli for, ponieważ są one powolne (przynajmniej w Pythonie).
Wiem, że w wielu sprawach z NumPy istnieją wcześniej zdefiniowane polecenia, które muszę po prostu zbadać, ale czy ty (jako bardziej doświadczeni programiści) masz ogólny proces myślowy, który przychodzi ci na myśl, gdy musisz coś powtórzyć?
Często mam coś takiego, co jest okropne i chcę tego uniknąć:
small_array = np.array(["one", "two"])
big_array = np.array(["one", "two", "three", "one"])
for i in range(len(small_array)):
for p in range(len(big_array)):
if small_array[i] == big_array[p]:
print "This item is matched: ", small_array[i]
Wiem, że istnieje wiele różnych sposobów osiągnięcia tego w szczególności, ale interesuje mnie ogólna metoda myślenia, jeśli istnieje.
I want to avoid for-loops as much as possible because they are slow (at least in Python).
Wygląda na to, że rozwiązujesz tutaj zły problem. Jeśli potrzebujesz iterować nad czymś, musisz iterować nad czymś; uzyskasz podobny wynik wydajności bez względu na to, jakiej konstrukcji Python używasz. Jeśli twój kod jest wolny, to nie dlatego, że maszfor
pętle; to dlatego, że wykonujesz niepotrzebną pracę lub pracę po stronie Pythona, którą można wykonać po stronie C. W twoim przykładzie wykonujesz dodatkową pracę; mogłeś to zrobić za pomocą jednej pętli zamiast dwóch.Odpowiedzi:
Jest to powszechna trudność koncepcyjna podczas nauki efektywnego używania NumPy . Zwykle przetwarzanie danych w Pythonie najlepiej wyraża się w postaci iteratorów , aby utrzymać niskie zużycie pamięci, zmaksymalizować możliwości równoległości z systemem I / O oraz zapewnić ponowne użycie i kombinację części algorytmów.
Ale NumPy odwraca to wszystko na lewą stronę: najlepszym podejściem jest wyrażenie algorytmu jako sekwencji operacji na całej tablicy , aby zminimalizować czas spędzany w wolnym interpreterze Pythona i zmaksymalizować ilość czasu spędzonego w szybko skompilowanych procedurach NumPy.
Oto moje ogólne podejście:
Zachowaj oryginalną wersję funkcji (co do której masz pewność, że jest poprawna), abyś mógł przetestować ją pod kątem poprawionych wersji zarówno pod względem poprawności, jak i szybkości.
Pracuj od wewnątrz: to znaczy zacznij od wewnętrznej pętli i sprawdź, czy można ją wektoryzować; kiedy to zrobisz, wyjdź o jeden poziom i kontynuuj.
Poświęć dużo czasu na czytanie dokumentacji NumPy . Jest tam wiele funkcji i operacji i nie zawsze są one genialnie nazwane, więc warto je poznać. W szczególności, jeśli pomyślisz, że „gdyby tylko istniała funkcja, która spełniała takie i takie”, to warto poświęcić dziesięć minut na jej szukanie. Zazwyczaj gdzieś tam jest.
Nie ma substytutu dla praktyki, więc dam wam kilka przykładowych problemów. Celem dla każdego problemu jest przepisać funkcję tak, że jest w pełni wektorowy , to znaczy tak, że składa się z sekwencji operacji NumPy na całych tablic, bez rodzimych pętli Pythona (bez
for
lubwhile
sprawozdania nie iteratorów lub listowe).Problem 1
Problem 2
Problem 3
Spojlery poniżej. Osiągniesz najlepsze wyniki, jeśli sam spróbujesz, zanim spojrzysz na moje rozwiązania!
odpowiedź 1
Odpowiedź 2
Odpowiedź 3
źródło
list
Aby przyspieszyć, musisz przeczytać swoje struktury danych i użyć odpowiednich.
W przypadku nietrywialnych rozmiarów małej tablicy i dużej tablicy (powiedzmy mała = 100 elementów i duża = 10.000 elementów) jednym ze sposobów jest posortowanie małej tablicy, a następnie iteracja po dużej tablicy i użycie wyszukiwania binarnego w celu znalezienia pasujących elementów w małej tablicy.
To spowodowałoby maksymalną złożoność czasową, O (N log N) (a dla małych małych i bardzo dużych dużych tablic jest bliżej O (N)), gdzie rozwiązaniem zagnieżdżonej pętli jest O (N ^ 2)
Jednak. to, które struktury danych są najbardziej wydajne, zależy w dużym stopniu od rzeczywistego problemu.
źródło
Możesz użyć słownika, aby znacznie zoptymalizować wydajność
To kolejny przykład:
źródło