Matrixwise subtraction yields vector - how to reshape to original logical matrix?

1 view (last 30 days)
Hi,
I am working with a large dataset for which I need to do multiple substractions between vectors, then summing across logically indexed values. Currently, I index the vector subtraction in a for loop, but it takes forever as I have to run that loop ~ 1.5M, several times, so I would like to move to matrixwise calculations.
Below is a short version of the crux of my question. If I have a matrix A and a matrix B, and I index the values I am interested in using a logical matrix (cmpMatrix), then I subtract B from A and want to get the mean per column. However, the logical indexing always reshapes into a vector, not a matrix:
A = rand(3);
B = rand(3);
cmpMatrix = A>=0.5 %in my situation, there are always unequal numbers of 0s and 1s per column
cmpMatrix =
3×3 logical array
1 0 1
0 1 1
1 0 0
%Issue: ans for the following line is a vector.
A(cmpMatrix)
ans =
0.9612
0.7870
0.9437
0.9813
0.5702
I'd like to take the mean of all the values that are indexed per column, so I'd need to be able to backtrack where the values in the vector came from. Ideally, I'd be able to do something like:
mean(A(cmpMatrix) - B(cmpMatrix),2)
And receive a 1 x 3 vector where B was subtracted from A at each logical 1, and then the mean was taken across the matrix columns, so as to get a mean per column.
How do I achieve that?
Thank you for your help.

Accepted Answer

Stephen23
Stephen23 on 15 Mar 2024
A = rand(3);
B = rand(3);
X = A>=0.5;
[~,C] = find(X);
M = accumarray(C,A(X)-B(X),[],@mean).'
M = 1×3
0.6699 0.0500 0.5998
  7 Comments
Voss
Voss on 18 Mar 2024
Edited: Voss on 18 Mar 2024
They're equal up to round-off error:
A = rand(104,8193);
B = rand(104,8193);
max(abs(Stephen(A,B)-Voss(A,B)),[],'all')
ans = 1.6653e-16
function M = Stephen(A,B)
X = A>=0.5;
[~,C] = find(X);
M = accumarray(C,A(X)-B(X),[],@mean).';
end
function M = Dyuman(A,B)
[m,n] = size(A);
Y = repmat(1:n,m,1); % modification for non-square A
X = A>=0.5;
M = accumarray(Y(X),A(X)-B(X),[],@mean).';
end
function result = Walter1(A,B)
cmpMatrix = A>=0.5;
result = arrayfun(@(IDX) mean(A(cmpMatrix(:,IDX),IDX)-B(cmpMatrix(:,IDX),IDX)), 1:size(A,2));
end
function result = Walter2(A,B)
cmpMatrix = A>=0.5;
result = cellfun(@mean, mat2cell(A(cmpMatrix) - B(cmpMatrix), sum(cmpMatrix,1), 1)).'; % removing temp variable, and transposing for consistency with other methods
end
function result = Voss(A,B)
A_temp = A;
B_temp = B;
idx = A >= 0.5;
A_temp(~idx) = NaN;
B_temp(~idx) = NaN;
result = mean(A_temp-B_temp,1,'omitnan');
end
Dyuman Joshi
Dyuman Joshi on 20 Mar 2024
I know and understand that they are round-off error; my point is why does it only occur in a single method and not in others, when all the methods use the same function (essentially the same operation)?

Sign in to comment.

More Answers (2)

Voss
Voss on 16 Mar 2024
A_temp = A;
B_temp = B;
idx = A >= 0.5;
A_temp(~idx) = NaN;
B_temp(~idx) = NaN;
result = mean(A_temp-B_temp,1,'omitnan');

Walter Roberson
Walter Roberson on 15 Mar 2024
One way:
result = arrayfun(@(IDX) mean(A(cmpMatrix(:,IDX),IDX)-B(cmpMatrix(:,IDX),IDX)), 1:size(A,2))
Chances are that this will be slower than looping.
Another way:
temp = A(cmpMatrix) - B(cmpMatrix);
result = cellfun(@mean, mat2cell(temp, sum(cmpMatrix,1), 1));
It would not surprise me if this is slower than looping.

Categories

Find more on Multidimensional Arrays in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!