2012-02-27 11 views
6

En MATLAB, tengo un for loop que tiene muchas interacciones para completar y llenar una matriz sparse. El programa es muy lento y me gustaría optimizarlo para verlo terminar pronto. En dos líneas uso el comando find y el editor de MATLAB me advierte que el uso de logical indexing en lugar de find mejorará el rendimiento. Mi código es bastante similar al presentado en mathworks newreader, mathworks newsreader recommendation, donde hay un vector de valores y un vector de valor único generado a partir de él. Utiliza find para obtener el índice en los valores únicos (para actualizar los valores en una matriz). Para ser breve, el código proporcionado es:¿Cómo sustituir los comandos `find` con` logical indexing` (MATLAB), para buscar posiciones de valores vectoriales de valores únicos?

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

Pero la última línea no es el índice, sino un vector de ceros y unos. Tengo un ejemplo ilustrativo, hago un conjunto de índices; tt=round(rand(1,6)*10):

tt = 3  7  1  7  1  7 

Hacer un único vector;

ttUNI = 1  3  7 

Uso encontrar para obtener el índice de posición del valor en el conjunto de valores únicos; find(ttUNI(:) == tt(1))

ans = 2 

Comparar con el uso de indexación lógica; (ttUNI(:) == tt(1))

ans = 
0 
1 
0 

Tener el valor 2 es mucho más útil que el vector binario cuando necesito para actualizar los índices de una matriz. Para mi matriz, puedo decir mat(find(ttUNI(:) == tt(1)), 4) y eso funciona. Considerando que el uso de (ttUNI(:) == tt(1)) necesita procesamiento posterior.

¿Existe una manera ordenada y eficiente de hacer lo que se necesita? ¿O es el uso de find inevitable en circunstancias como estas?

ACTUALIZACIÓN: voy a incluir aquí el código como se recomienda por el usuario: @Jonas para dar una mejor penetración en el problema que estoy teniendo y reportar algunos de los resultados de la herramienta de perfiles.

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 

Aquí UNIQUE_LENGTH = 223482 y size(network,1)=273209. Rand el profiler tool durante unos minutos, lo que no fue suficiente tiempo para que termine el programa, sino para alcanzar un estado estable cuando la relación de tiempos no cambia demasiado. Atensor_row_num = find(NUM_UNI.. es 45.6% y Atensor_col_num = find(NUM_UNI... es 43.4%. La línea con Atensor(Atensor_row_num,Atenso... que asigna valores a la matriz sparse, es solo 8.9%. La longitud del vector NUM_UNIQUE es bastante grande, por lo que find es un aspecto importante del código; incluso más importante que la manipulación de matriz dispersa. Cualquier mejora aquí sería significativa. No sé si hay una progresión lógica más eficiente para que este algoritmo proceda en lugar de tomar el enfoque directo de reemplazar find.

+0

Yo sólo quería añadir que, en lo que puedo decir, que la alerta el mensaje es más o menos desencadenado por cada llamada a encontrar. Recientemente encontré una situación en la que la versión indexada lógicamente era considerablemente más lenta que la que llamaba find(). Si se trata de una situación de tiempo crítico, lo intentaría de ambas formas. –

Respuesta

8

find es de hecho inevitable bajo ciertas circunstancias. Por ejemplo, si desea recorrer los índices, es decir

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

o si usted quiere hacer la indexación multi-nivel

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

o si desea que los primeros n buenos valores

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

En su caso, usted puede ser capaz de evitar la llamada a find mediante el uso de las salidas adicionales de unique

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

Antes de intentar optimizar su código arreglando lo que cree que lleva tiempo, le sugiero que ejecute el generador de perfiles en su código para comprobar lo que realmente lleva tiempo. Y luego posiblemente puedas publicar el código de tu bucle real, y podamos ayudarte.

+0

Agregué los resultados del generador de perfiles del código en ejecución y el código de bucle real. aclamaciones. – Vass

5

Si desea encontrar el índice de los valores verdaderos en un vector lógico, puede hacer lo siguiente:

>> 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 
Cuestiones relacionadas