如何在MATLAB中使用2-D掩码索引3-D矩阵?

13

假设我有一个X×Y×Z的数据矩阵D,还有一个X×Y的掩码矩阵M。我的目标是,当M中的(Xi,Yi)为false时,将D中的元素(Xi,Yi,:)设置为NaN。

有没有办法避免使用循环来达到这个目的?我尝试使用ind2sub,但失败了:

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

我怀疑我在这里漏掉了一些显而易见的东西。(:

3个回答

13
你可以通过使用REPMAT函数将逻辑掩码M在第三维度上复制,使其与D相同大小。然后索引即可:
D_masked = D;
D_masked(repmat(~M,[1 1 size(D,3)])) = NaN;
如果不希望复制掩码矩阵,则有另一种选择。可以先找到一组线性索引,用于在其中M等于0,然后将该集合复制size(D,3)次,然后将每个索引集移位多个numel(M),使其索引D的第三维中的不同部分。我将在此处使用BSXFUN进行说明:
D_masked = D;
index = bsxfun(@plus,find(~M),(0:(size(D,3)-1)).*numel(M));
D_masked(index) = NaN;

啊,当然,那样可以行。不过对于巨大的D和M维度,最好还是不要复制它... - Matt Mizumi
@Matt:由于M是一个逻辑矩阵,每个元素只使用1个字节,因此复制它不会像复制双精度矩阵那样占用太多内存。实际上,复制后的M版本仅使用D总内存的1/8。 - gnovice
2
@Matt:为了完整性,我添加了另一种解决方案,避免了对M的复制。如果一个非常大的矩阵M中只有很少的零值,从内存使用的角度来看,这个新的解决方案可能更加理想。 - gnovice
2
我特别喜欢使用BSXFUN查找线性索引的解决方案。感谢您添加这个功能。 - Matt Mizumi

0

Reshape(重塑)是基本上免费的,您可以在此处使用它作为高效解决方案。将整个问题简化为二维问题。

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

-3

我的 Matlab 有点生疏,但我认为逻辑索引应该可行:

D_masked = D;
D_masked[ M ] = NaN;

(这可能可以合并为一个语句,右侧带有条件表达式...)

1
啊,我应该在“我尝试过的事情”中包括那个 :-) 如果你这样做,你只会掩盖第一个Z维度,所以D(:,:,1)将应用掩码,但D(:,:,2)不会。感谢您的建议! - Matt Mizumi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接