Pracuję z Matlabem.
Mam binarną macierz kwadratową. Dla każdego wiersza znajduje się jeden lub więcej wpisów 1. Chcę przejrzeć każdy wiersz tej macierzy i zwrócić indeks tych 1s i zapisać je we wpisie komórki.
Zastanawiałem się, czy można to zrobić bez zapętlania wszystkich wierszy tej macierzy, ponieważ w Matlabie pętla jest naprawdę wolna.
Na przykład moja matryca
M = 0 1 0
1 0 1
1 1 1
W końcu chcę coś takiego
A = [2]
[1,3]
[1,2,3]
Podobnie A
jak komórka.
Czy istnieje sposób na osiągnięcie tego celu bez użycia pętli for, w celu szybszego obliczenia wyniku?
matlab
vectorization
ftxx
źródło
źródło
for
pętli? W przypadku tego problemu, w przypadku nowoczesnych wersji MATLAB, podejrzewam, żefor
pętla będzie najszybszym rozwiązaniem. Jeśli masz problem z wydajnością, podejrzewam, że szukasz niewłaściwego miejsca na rozwiązanie w oparciu o nieaktualne porady.cellfun
.1
jest w typowym rzędzie? Nie spodziewałbym się, żefind
pętla zajmie coś blisko 30s dla czegoś wystarczająco małego, aby zmieściło się w pamięci fizycznej.Odpowiedzi:
Na dole tej odpowiedzi znajduje się kod porównawczy, ponieważ wyjaśniłeś, że interesuje Cię wydajność, a nie arbitralne unikanie
for
pętli.W rzeczywistości myślę, że
for
pętle są prawdopodobnie najbardziej wydajną opcją tutaj. Od czasu wprowadzenia „nowego” (2015b) silnika JIT pętle ( źródłowe )for
nie są z natury wolne - w rzeczywistości są zoptymalizowane wewnętrznie.Można zobaczyć od benchmarku, że
mat2cell
opcja oferowana przez ThomasIsCoding tutaj jest bardzo powolny ...Jeśli pozbywamy się tej linii, aby skala była wyraźniejsza, wówczas moja
splitapply
metoda jest dość powolna, opcja akumulacji tablicy obchardon jest nieco lepsza, ale najszybsze (i porównywalne) opcje albo używająarrayfun
(jak sugeruje Thomas), albofor
pętli. Pamiętaj, że w większości przypadkówarrayfun
jest tofor
ukryta pętla, więc nie jest to zaskakujący remis!Polecam użyciefor
pętli dla zwiększenia czytelności kodu i najlepszej wydajności.Edytuj :
Jeśli założymy, że zapętlenie jest najszybszym podejściem, możemy dokonać optymalizacji wokół
find
polecenia.konkretnie
Zrób
M
logiczne. Jak pokazuje poniższy wykres, może to być szybsze dla stosunkowo małychM
, ale wolniejsze z kompromisem konwersji typu dla dużychM
.Użyj logiki,
M
aby zindeksować tablicę1:size(M,2)
zamiast używaćfind
. Pozwala to uniknąć najwolniejszej części pętli (find
polecenia) i przewyższa narzut związany z konwersją typów, co czyni ją najszybszą opcją.Oto moja rekomendacja dla najlepszej wydajności:
Dodałem to do poniższego testu porównawczego, oto porównanie podejść w stylu pętli:
Kod porównawczy:
źródło
M
. Jeśli na przykład zapełnione jest tylko 5% elementów,M = randi([0,20],N) == 20;
wówczasfor
pętla jest zdecydowanie najwolniejsza, a twojaarrayfun
metoda wygrywa.accumarray
bezind2sub
, ale jest wolniejsze niżfor
pętlaMożesz spróbować
arrayfun
jak poniżej, które przesuwają się przez rzędyM
lub (wolniejsze podejście do
mat2cell
)źródło
arrayfun
jest to po prostu przebranie w pętli, więc może się nie udać na obu frontach 1) unikania pętli i 2) szybkiego, zgodnie z oczekiwaniami OPEdycja : Dodałem test porównawczy, wyniki pokazują, że pętla for jest bardziej wydajna niż
accumarray
.Możesz użyć
find
iaccumarray
:Macierz jest transponowana (
A'
), ponieważfind
grupuje według kolumn.Przykład:
Wynik:
Reper:
Wynik:
Pętla for jest bardziej wydajna niż
accumarray
...źródło
Za pomocą accumarray :
źródło
MM{I} = find(M(I, :))
.ind2sub
:[ii, jj] = find(M); accumarray(ii, jj, [], @(x){x})
Możesz użyć strfind :
źródło
string
typów, a nie znaków? Istnieje wiele optymalizacji dla ciągów, dlatego też istnieją ...