How do I speed up my variable lookup algorithm?
1 vue (au cours des 30 derniers jours)
I have two 3D structures I'm trying to analyze. (1) slantvals is a 2847048x1 double containing label values; (2) var is identical size 224x320x320 int16 containing the variable I'm interested in.
Note: slantvals is a deconstruction of a 3D volume and has been ordered by spatial location. slantvals and var come from the same original grid size (224x320x320) but during the process of converting to 1D array I remove the zero values so instead of having a 23937600x1 array I only have a 2847048x1 array in the slantvals variable.
My goal is to use the labeled regions in slantvals to identify the entries in var that correspond to each label (203 total). I would like to end up with a 2D variable violindata that stores the entries from var that correspond to each label, as follows:
Label 1 | Label 2 | Label 3 | Label ... | Label N
Entry 1 .. .. .. .. ..
Entry 2 .. .. .. .. ..
Entry . .. .. .. .. ..
Entry N .. .. .. .. ..
I'm currently accomplishing this using the following nested loop:
for label=0:max(slantseg,,'all') %pre-defined upper limit for-loop
locs=find(slantvals==label); %locs is an Nx1 vector with size varying by the amount of entries found to correspond to `label` each loop
coords=slantinds(locs,:); %coords reconstructs the spatial location of every index from `locs` (e.g. 178936 --> [148,68,135])
for point=1:length(coords) %For each identified coordinate,
coords_x = coords(point,1);
coords_y = coords(point,2);
coords_z = coords(point,3);
violindata(point,label+1)=var(coords_x,coords_y,coords_z); %read the data in `var` at that location and store it
This code seems to work reliably and the variable violindata is correctly constructing as I'm intending, however it is taking an absurdly long time to process. I'm projecting easily more than 5 hours for this set of for-loops to complete.
Question: Is there any way for me to speed up this for-loop or construct this algorithm in a better way?
I've seen documentation on sliced variables but am very uncertain how to address that in my particular case - any help would be greatly appreciated!
Jiri Hajek le 6 Oct 2022
It seems your use of the find functiois unnecessary. This function takes a lot of time, which you could verify by profiling your code. There's a much faster option, namely to use logical indices instead:
locs = (slantvals==label);
coords = slantinds(locs,:);
Bruno Luong le 7 Oct 2022
Modifié(e) : Bruno Luong le 7 Oct 2022
% Fake data
slantvals = randi([0 10], 1, 224*320*320);
var = rand([5,5,5]);
slantinds = randi(length(var),[numel(slantvals),3]);
[valsorted,is] = sort(slantvals); % sort by label
coords = slantinds(is,:); % range slantinds in the same order (sorted by label)
[len, label, ~, subidx] = runlengthencoder(valsorted); % function below, get the subidx by label
gr = label+1;
m = max(subidx);
n = max(gr);
violindata = nan(m,n);
idxdest = sub2ind(size(violindata),subidx,repelem(gr,len));
idxsrc = sub2ind(size(var),coords(:,1),coords(:,2),coords(:,3));
violindata(idxdest) = var(idxsrc);
function [len, v, gr, subidx] = runlengthencoder(X)
% [len, v, gr, subidx] = runlengthencoder(X)
% Run-length encoder
% X is (1 x n) row vector, column is also allowed
% len: integer arrays (1 x m)
% v: (1 x m) ordering subset of X, such that two adjadcent elements are differents
% and X = replelem(v, len)
% gr: 1:m
% subidx: (1 x n) integer, interior indexes of X with in the group
% See also: runlengthdecoder
X = reshape(X, 1, );
n = size(X,2);
b = [true, diff(X)~=0];
ij = find([b, true]);
len = diff(ij);
v = X(b);
if nargout >= 3
gr = repelem(1:length(len),len);
if nargout >= 4
if n > 0 % end indexing requires non empty arrays
subidx = ones(1,n);
subidx(ij(2:end-1)) = 1-len(1:end-1);
subidx = cumsum(subidx);
subidx = ;
end % runlengthencoder