13

Suppose I have D, an X-by-Y-by-Z data matrix. I also have M, an X-by-Y "masking" matrix. My goal is to set the elements (Xi,Yi,:) in D to NaN when (Xi,Yi) in M is false.

Is there any way to avoid doing this in a loop? I tried using ind2sub, but that fails:

M = logical(round(rand(3,3))); % mask
D = randn(3,3,2); % data

% try getting x,y pairs of elements to be masked
[x,y] = ind2sub(size(M),find(M == 0));
D_masked = D;
D_masked(x,y,:) = NaN; % does not work!

% do it the old-fashioned way
D_masked = D;
for iX = 1:size(M,1)
    for iY = 1:size(M,2)
        if ~M(iX,iY), D_masked(iX,iY,:) = NaN; end
    end
end

I suspect I'm missing something obvious here. (:

gnovice
  • 125,304
  • 15
  • 256
  • 359
Matt Mizumi
  • 1,193
  • 1
  • 11
  • 27

3 Answers3

13

You can do this by replicating your logical mask M across the third dimension using REPMAT so that it is the same size as D. Then, index away:

D_masked = D;
D_masked(repmat(~M,[1 1 size(D,3)])) = NaN;

If replicating the mask matrix is undesirable, there is another alternative. You can first find a set of linear indices for where M equals 0, then replicate that set size(D,3) times, then shift each set of indices by a multiple of numel(M) so it indexes a different part of D in the third dimension. I'll illustrate this here using BSXFUN:

D_masked = D;
index = bsxfun(@plus,find(~M),(0:(size(D,3)-1)).*numel(M));
D_masked(index) = NaN;
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • ah, of course, that works. for giant dimensions of D and M though it may still be desirable not to have to replicate it... – Matt Mizumi Aug 04 '10 at 16:45
  • @Matt: Since `M` is a logical matrix, it only uses 1 byte per element, so replicating it won't use up nearly as much memory as replicating matrices of doubles. In fact, the replicated version of `M` will use up only 1/8th the total memory that `D` does. – gnovice Aug 04 '10 at 16:50
  • 2
    @Matt: For completeness, I added another solution that avoids replication of `M`. If there are only a few zero values in a very large matrix `M`, this new solution may be more desirable from a memory-usage standpoint. – gnovice Aug 04 '10 at 17:09
  • 2
    =) I especially like the finding-linear-indices by BSXFUN solution. Thanks for adding that in. – Matt Mizumi Aug 04 '10 at 17:14
0

Reshape is basically for free, you can use it here for an efficient solution. reducing the whole to a 2d problem.

sz=size(D);
D=reshape(D,[],sz(3)); %reshape to 2d
D(isnan(M(:)),:)=nan; %perform the operation on the 2d matrix
D=reshape(D,sz); %reshape back to 3d
Daniel
  • 36,610
  • 3
  • 36
  • 69
-3

My Matlab is a bit rusty but I think logical indexing should work:

D_masked = D;
D_masked[ M ] = NaN;

(which probably can be combined into one statement with a conditional expression on the rhs...)

c-urchin
  • 4,344
  • 6
  • 28
  • 30
  • 1
    ah, I should have included that in the "things I tried" :-) if you do that you only mask the first Z dimension, so D(:,:,1) will have the mask applied but not D(:,:,2). thanks for the suggestion though! – Matt Mizumi Aug 04 '10 at 16:27