2012-02-27 9 views
6

W programie MATLAB, mam for loop, który ma wiele interakcji przejść i wypełnić matrycę sparse. Program jest bardzo powolny i chciałbym go zoptymalizować, aby zakończyć go niedługo. W dwóch wierszach używam polecenia find, a edytor MATLAB ostrzega mnie, że użycie logical indexing zamiast find poprawi wydajność. Mój kod jest bardzo podobny do tego przedstawionego nowicjuszowi mathworks, mathworks newsreader recommendation, gdzie znajduje się wektor wartości i wektor unikalnej wartości z niego wygenerowanej. Używa find do uzyskania indeksu w unikatowych wartościach (do aktualizacji wartości w macierzy). Mówiąc krótko, kod podany jest:Jak zastąpić polecenia `find` za pomocą` indeksowania logicznego` (MATLAB), aby wyszukać wartości wartości wektorowych o unikalnych wartościach?

 positions = find(X0_outputs == unique_outputs(j,1)); 
% should read 
    positions = X0_outputs == unique_outputs(j,1); 

Jednak ostatnia linia nie jest indeksem, ale wektorem zer i jedynek. Mam przykład ilustrujący, zrób zestaw indeksów; tt=round(rand(1,6)*10):

tt = 3  7  1  7  1  7 

Stwórz unikalny wektor;

ttUNI = 1  3  7 

Wykorzystanie znaleźć, aby uzyskać indeks pozycję wartości w zbiorze unikalnych wartości; find(ttUNI(:) == tt(1))

ans = 2 

Porównaj z wykorzystaniem logicznego indeksowania; (ttUNI(:) == tt(1))

ans = 
0 
1 
0 

o wartości 2 jest dużo bardziej przydatne niż tego wektora binarnego kiedy muszę zaktualizować indeksy dla macierzy. Dla mojej matrycy mogę powiedzieć mat(find(ttUNI(:) == tt(1)), 4) i to działa. Podczas gdy użycie (ttUNI(:) == tt(1)) wymaga przetwarzania.

Czy istnieje schludny i skuteczny sposób robienia tego, co jest potrzebne? A może nie jest to konieczne w takich okolicznościach?

UPDATE: będę zawierać kod tutaj jako zalecana przez użytkownika: @Jonas dać lepszy wgląd w problem, który mam i zgłoś niektóre z wyników narzędzia Profiler jest.

ALL_NODES = horzcat(network(:,1)',network(:,2)'); 
NUM_UNIQUE = unique(ALL_NODES);%unique and sorted  
UNIQUE_LENGTH = length(NUM_UNIQUE); 
TIME_MAX = max(network(:,3)); 
WEEK_NUM = floor((((TIME_MAX/60)/60)/24)/7);%divide seconds for minutes, for hours, for days and how many weeks 
%initialize tensor of temporal networks 
temp = length(NUM_UNIQUE); 
%making the tensor a sparse 2D tensor!!! So each week is another replica of 
%the matrix below 
Atensor = sparse(length(NUM_UNIQUE)*WEEK_NUM,length(NUM_UNIQUE)); 
WEEK_SECONDS = 60*60*24*7;%number of seconds in a week 

for ii=1:size(network,1)%go through all rows/observations 
    WEEK_NOW = floor(network(ii,3)/WEEK_SECONDS) + 1; 
    if(WEEK_NOW > WEEK_NUM) 
     disp('end of weeks') 
     break 
    end 
    data_node_i = network(ii,1); 
    Atensor_row_num = find(NUM_UNIQUE(:) == data_node_i)... 
     + (WEEK_NOW-1)*UNIQUE_LENGTH; 
    data_node_j = network(ii,2); 
    Atensor_col_num = find(NUM_UNIQUE(:) == data_node_j); 
    %Atensor is sparse 
    Atensor(Atensor_row_num,Atensor_col_num) = 1;   
end 

Tutaj UNIQUE_LENGTH = 223482 i size(network,1)=273209. Przez kilka minut robiłem randkę, co nie było wystarczającym czasem na zakończenie programu, ale na osiągnięcie stanu ustalonego, gdy stosunek czasów nie zmieniłby się zbytnio. Atensor_row_num = find(NUM_UNI.. jest 45,6% i Atensor_col_num = find(NUM_UNI... jest 43,4%. Linia z Atensor(Atensor_row_num,Atenso..., która przydziela wartości do macierzy sparse, jest tylko 8.9%. Długość wektora NUM_UNIQUE jest dość duża, więc find jest ważnym aspektem kodu; jeszcze ważniejsze niż rzadka manipulacja matrycą. Każda poprawa tutaj byłaby znacząca. Nie wiem, czy istnieje bardziej wydajny postęp logiczny dla tego algorytmu, aby postępować, jak również zamiast prostego podejścia do zastępowania find.

+0

Chciałem tylko dodać, że o ile mogę powiedzieć, że ostrzeżenie wiadomość jest w mniejszym lub większym stopniu wywoływana przez każde wezwanie do znalezienia. Niedawno natknąłem się na sytuację, w której indeksowana logicznie wersja była znacznie wolniejsza niż ta, którą nazwałem find(). Jeśli jest to sytuacja krytyczna w czasie, spróbowałbym obu sposobów. –

Odpowiedz

8

find jest rzeczywiście nieuniknione w pewnych okolicznościach. Na przykład, jeśli chcesz zapętlić indeksy, np.

idx = find(someCondition); 
for i = idx(:)' 
    doSomething 
end 

lub jeśli chcesz zrobić wielopoziomowy indeksowanie

A = [1:4,NaN,6:10]; 
goodA = find(isfinite(A)); 
everyOtherGoodEntry = A(goodA(1:2:end)); 

lub jeśli chcesz pierwszych n dobre wartości

A = A(find(isfinite(A),n,'first'); 

W twoim przypadku, być może uda się uniknąć połączenie z find przy użyciu dodatkowych wyjść: unique

[uniqueElements,indexIntoA,indexIntoUniqueElements] = unique(A); 

Zanim spróbujesz zoptymalizować swój kod, naprawiając to, co uważasz, że wymaga czasu, sugeruję uruchomienie profilera na kodzie, aby sprawdzić, co naprawdę wymaga czasu. Następnie możesz opublikować kod rzeczywistej pętli i być może pomożemy.

+0

Dodałem wyniki profilera z działającego kodu i rzeczywistego kodu pętli. Twoje zdrowie. – Vass

5

Jeśli chcesz znaleźć indeks prawdziwych wartości w logicznej wektora, można wykonać następujące czynności:

>> r = rand(1,5) 
r = 
    0.5323 0.3401 0.4182 0.8411 0.2300 

>> logical_val = r < 0.5   % Check whether values are less than 0.5 
logical_val = 
    0  1  1  0  1 

>> temp = 1:size(r,2)    % Create a vector from 1 to the size of r 
temp = 
    1  2  3  4  5 

>> temp(logical_val)    % Get the indexes of the true values 
ans = 
    2  3  5 
Powiązane problemy