2

I've a large D Matrix of size MxNxK. Given a binary mask B of size MxN, I would like to split the matrix D into two submatrices: D0 and D1, in such a way that matrix D0 has the values of matrix D associated with the 0's in the binary mask. The same is valid for D1, but by using the 1's in the binary mask. Currently, I'm solving this issue by using loops, but I'm wondering if there's a more efficient way to solve that?

mat_zeros = [];
mat_ones = [];

for m=1:M
    for n=1:N

        matval = matrixbig(m,n,:);
        matval = matval(:)'; % mapping matval to a K-dimensional vector

        if (binmask(m,n) == 1)
            mat_ones   = [mat_ones; matval];
        elseif (binmask(m,n) == 0)
            mat_zeros   = [mat_zeros; matval];
        end
    end
end

All suggestions are welcomed ;-)

Tin
  • 1,006
  • 1
  • 15
  • 27
  • Have a look at this [SO question](http://stackoverflow.com/questions/3407525/how-can-i-index-a-3-d-matrix-with-a-2-d-mask-in-matlab) – Maurits Jan 06 '12 at 16:38

3 Answers3

1

Iterating over the K dimension leads to more efficient code with only one loop. See the Shorter algorithm section of code below:

% Some data
clear; M = 3; N = 2; K = 4;
matrixbig = rand(M,N,K);
binmask = round(matrixbig(:,:,1));

% Original algorithm
mat_zeros = []; mat_ones = [];
for m=1:M
  for n=1:N
    matval = matrixbig(m,n,:);
    matval = matval(:)';

    if (binmask(m,n) == 1)
      mat_ones   = [mat_ones; matval];
    elseif (binmask(m,n) == 0)
      mat_zeros   = [mat_zeros; matval];
    end
  end
end 

% Shorter algorithm
mat_zeros1 = []; mat_ones1 = [];
mask = (binmask == 1)';
for k = 1:K
  matval = matrixbig(:,:,k)';
  mat_ones1  = [mat_ones1,  matval(mask)];
  mat_zeros1 = [mat_zeros1, matval(~mask)];
end

% Compare results of two algorithms
isequal(mat_ones,  mat_ones1 )
isequal(mat_zeros, mat_zeros1 )
Kavka
  • 4,191
  • 16
  • 33
1

You can also do this without any loops at all, by replicating the 2d binary mask into a 3d mask the size of your data, and then doing logical indexing.

binmask_big = repmat(binmask, [1 1 K]);
mat_ones = matrixbig(binmask_big==1);
mat_zeros = matrixbig(binmask_big==0);
Matt
  • 2,846
  • 2
  • 17
  • 12
  • @ Matt, thanks, but ideally, I would like that `mat_ones` and `mat_zeros` they both have `K` columns. Following your suggestion, I get 1 column matrices. – Tin Jan 07 '12 at 10:32
0

The most efficient way is to use linear indexing and avoid loops altogether. You must precompute the indices of ones and zeros in the mask. The following should work:

% You must define M,N in order for the code to work

mat_zeros = [];
mat_ones = [];

indOnes=find(binmask==1);  %returns linear indices
indZeros=find(binmask==0); %returns linear indices

mat_ones   = [matrixbig(indOnes) matrixbig(indOnes+M*N) matrixbig(indOnes+2*M*N)];
mat_zeros  = [matrixbig(indZeros) matrixbig(indZeros+M*N) matrixbig(indZeros+2*M*N)];

And there you have it!

Jorge
  • 784
  • 5
  • 16