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
.
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. –