I would like to apply a 2D mask to a 3D matrix, then average the non-masked values. In the example below, the mean is calculated in two ways, (a) with bsxfun and (b) in a loop which sums values and divides by the count. The results aren't the same, though. Can you spot my error, which I suspect is in approach (b)?
nRow = 200; nCol = 100; nChannel = 10;bigMatrix = rand(nRow, nCol, nChannel); % 3D matrix of values that we want to mask
mask = ones(nRow, nCol); % Make a 2D mask
mask(1:25, 26:50) = NaN; % Mask set to NaN where values should be excluded
%%(a) Use bsxfun to substitute NaNs for masked values in bigMatrix
% Since mask values are either NaN or 1, can mask by multiplying
maskedByMult = bsxfun(@times, bigMatrix, cast(mask, 'like', bigMatrix));% Average the non-nan values
meanByBsxfun = squeeze(mean(mean(maskedByMult, 'omitnan'), 'omitnan')); %%(b) Mask by loop
nGoodValues = 0; % Count of unmasked values used in later calculation of their mean
sumValues = zeros(nChannel, 1); % Sums will be added to this
for iRow = 1:length(nRow) for iCol = 1:length(nCol) if isfinite(mask(iRow, iCol)) % Check if this x,y location is masked out
nGoodValues = nGoodValues + 1; sumValues = sumValues + squeeze(bigMatrix(iRow, iCol, :)); end endendmeanByLoop = sumValues/nGoodValues; % Get the mean
%%Show they differ
figure('Name', 'Compare two ways of getting the mean');plot(1:10, meanByBsxfun); hold on;plot(1:10, meanByLoop, '--');legend('Using bsxfun', 'Using a loop');
Best Answer