Biorąc pod uwagę tablicę NumPy A , jaki jest najszybszy / najbardziej efektywny sposób zastosowania tej samej funkcji f do każdej komórki?
Załóżmy, że będziemy przypisać do A (i, j) do f (A (i, j)) .
Funkcja f nie ma wyjścia binarnego, więc operacje maskowania nie pomogą.
Czy „oczywista” iteracja podwójnej pętli (przez każdą komórkę) jest optymalnym rozwiązaniem?
Odpowiedzi:
Możesz po prostu wektoryzować funkcję, a następnie zastosować ją bezpośrednio do tablicy Numpy za każdym razem, gdy jej potrzebujesz:
Prawdopodobnie lepiej jest określić jawny typ wyjścia bezpośrednio podczas wektoryzacji:
źródło
vectorize
opisie funkcji: Funkcja wektoryzacji jest dostarczana głównie dla wygody, a nie dla wydajności. Implementacja jest zasadniczo pętlą for. Więc najprawdopodobniej nie przyspieszy to wcale procesu.vectorize
określa typ zwrotu. To spowodowało błędy.frompyfunc
jest nieco szybszy, ale zwraca tablicę obiektów dtype. Oba skalary kanałów, a nie wiersze ani kolumny.np.vectorize
mojej funkcji (która wykorzystuje RK45) daje mi przyspieszenie ~ 20 razyPodobne pytanie brzmi: mapowanie tablicy NumPy w miejscu . Jeśli możesz znaleźć ufunc dla swojej f (), powinieneś użyć parametru out.
źródło
Jeśli pracujesz z liczbami i
f(A(i,j)) = f(A(j,i))
, możesz użyć scipy.spatial.distance.cdist, definiując f jako odległość międzyA(i)
aA(j)
.źródło
Uważam, że znalazłem lepsze rozwiązanie. Pomysł, aby zmienić funkcję na uniwersalną funkcję Pythona (patrz dokumentacja ), która może wykonywać równoległe obliczenia pod maską.
Można napisać swój własny dostosowany
ufunc
w C, co z pewnością jest bardziej wydajne, lub wywołaćnp.frompyfunc
, co jest wbudowaną metodą fabryczną. Po przetestowaniu jest to bardziej wydajne niżnp.vectorize
:Przetestowałem również większe próbki, a poprawa jest proporcjonalna. Aby porównać wyniki innych metod, zobacz ten post
źródło
Gdy tablica 2d (lub tablica nd) jest ciągła C lub F, to zadanie mapowania funkcji na tablicę 2d jest praktycznie takie samo jak zadanie mapowania funkcji na tablicę 1d - po prostu trzeba to zobaczyć w ten sposób, np
np.ravel(A,'K')
. przez .Możliwe rozwiązanie dla macierzy 1d zostało omówione na przykład tutaj .
Jednak, gdy pamięć tablicy 2d nie jest ciągła, sytuacja jest nieco bardziej skomplikowana, ponieważ chciałoby się uniknąć ewentualnych błędów w pamięci podręcznej, jeśli oś jest obsługiwana w złej kolejności.
Numpy ma już maszynę do obróbki osi w możliwie najlepszej kolejności. Jedną z możliwości wykorzystania tej maszyny jest
np.vectorize
. Jednak dokumentacja numpy na tematnp.vectorize
stwierdza, że jest ona "dostarczana głównie dla wygody, a nie dla wydajności" - powolna funkcja Pythona pozostaje wolną funkcją Pythona z całym związanym z nią narzutem! Inną kwestią jest ogromne zużycie pamięci - zobacz na przykład ten post SO .Kiedy ktoś chce mieć działanie funkcji C, ale użyć maszyny numpy, dobrym rozwiązaniem jest użycie numba do tworzenia ufuncs, na przykład:
Z łatwością bije,
np.vectorize
ale także wtedy, gdy ta sama funkcja byłaby wykonywana jako mnożenie / dodawanie tablicy numpy, tjZobacz dodatek do tej odpowiedzi dla kodu pomiaru czasu:
Wersja Numby (zielona) jest około 100 razy szybsza niż funkcja Pythona (tj.
np.vectorize
), Co nie jest zaskakujące. Ale jest również około 10 razy szybsza niż funkcja numpy, ponieważ wersja numbas nie wymaga tablic pośrednich, a zatem bardziej wydajnie wykorzystuje pamięć podręczną.Chociaż podejście ufunc firmy numba jest dobrym kompromisem między użytecznością a wydajnością, nadal nie jest to najlepsze, co możemy zrobić. Nie ma jednak srebrnej kuli ani podejścia, które najlepiej nadaje się do każdego zadania - trzeba zrozumieć, jakie są ograniczenia i jak można je złagodzić.
Na przykład, dla transcendentalnych funkcji (np
exp
,sin
,cos
) Numba nie daje żadnych korzyści w porównaniu z numpy użytkownikanp.exp
(nie ma tymczasowe tablice tworzone - głównym źródłem prędkości-up). Jednak moja instalacja Anacondy wykorzystuje VML Intela dla wektorów większych niż 8192 - po prostu nie może tego zrobić, jeśli pamięć nie jest ciągła. Dlatego lepiej byłoby skopiować elementy do ciągłej pamięci, aby móc używać VML Intela:Dla uczciwości porównania wyłączyłem równoległość VML (zobacz kod w załączniku):
Jak widać, po uruchomieniu VML, narzut kopiowania jest więcej niż kompensowany. Jednak gdy dane stają się zbyt duże dla pamięci podręcznej L3, korzyść jest minimalna, ponieważ zadanie ponownie wiąże się z przepustowością pamięci.
Z drugiej strony numba może również używać SVML Intela, jak wyjaśniono w tym poście :
i używając języka VML z wynikami zrównoleglania:
Wersja numba ma mniej narzutów, ale dla niektórych rozmiarów VML bije SVML nawet pomimo dodatkowego narzutu kopiowania - co nie jest zaskoczeniem, ponieważ ufunks numba nie jest zrównoleglony.
Aukcje:
A. porównanie funkcji wielomianu:
B. porównanie
exp
:źródło
Wszystkie powyższe odpowiedzi dobrze się porównują, ale jeśli potrzebujesz użyć niestandardowej funkcji do mapowania, a masz
numpy.ndarray
, i musisz zachować kształt tablicy.Porównałem tylko dwa, ale zachowa kształt
ndarray
. Do porównania użyłem tablicy z 1 milionem wpisów. Tutaj używam funkcji kwadratowej. Przedstawię ogólny przypadek dla tablicy n-wymiarowej. W przypadku dwuwymiarowych po prostu wykonajiter
2D.Wynik
tutaj możesz wyraźnie zobaczyć
numpy.fromiter
funkcję kwadratu użytkownika, użyj dowolnego wyboru. Jeśli funkcja jest zależna odi, j
indeksów tablicy, iteruj po rozmiarze tablicy, takim jakfor ind in range(arr.size)
, użyj,numpy.unravel_index
aby uzyskaći, j, ..
na podstawie indeksu 1D i kształtu tablicy numpy.unravel_indexTa odpowiedź jest inspirowana moją odpowiedzią na inne pytanie tutaj
źródło