Intro: I need to find the greatest/smallest possible deviations from the average in some given Matlab vectors. The issue is that, due to the large dimensions of the arrays involved, I cannot explicitly construct such vectors. Therefore, I wonder whether there is a smarter way to proceed. I summarise below the procedure that I would implement if there were no memory constraints and then present my question.
(1) Consider 28 matrices in Matlab A{1},..., A{28}
.
For each j=1,...,28
, A{j}
has 4 columns. The number of rows of A{j}
can be different across j=1,..., 28
and is stored in the vector r
.
clear
rng default
A=cell(28,1);
r=randi(10000,28,1) 10000; (x1
for j=1:28
A{j}=randn(r(j),4); %r(j)x4
end
(2) For each j=1,...,28
, let b{j}
be the r(j) x 1
vector that is obtained by summing the first two rows of A{j}
and subtracting the last two rows of A{j}
:
b=cell(28,1);
for j=1:28
b{j}=A{j}(:,1) A{j}(:,2)-A{j}(:,3)-A{j}(:,4); %r(j)x1
end
(3) Let B
be the R x 28
matrix that is obtained as a 28-D grid from the vectors b{1},...,b{28}
:
%[ca, cb, cc, cd, ce, ...] = ndgrid(b{1}, b{2}, b{3} , ..., b{28});
%B(:,1)=ca(:);
%B(:,2)=cb(:);
%...
%B(:,28)=...;
c=cell(28,1);
[c{:}]=ndgrid(b{:});
c=cellfun(@(x)x(:),c,'UniformOutput',false);
B=[c{:}];
Apologies for the incomplete code. As you can imagine, this is the step where I have issues as explained below.
(4) For each row of B
, I compute the difference between such row and its mean value and store the results in a R x 28
matrix D
:
%R=size(B,1);
%D=zeros(R,28);
%for t=1:R
% D(t,:)=B(t,:)-mean(B(t,:));
%end
D=B-mean(B,2);
(5) For each j=1,...,28
, I compute the min and max value of D(:,j)
and store it in a matrix F
F=zeros(2,28);
for j=1:28
F(1,j)=min(D(:,j));
F(2,j)=max(D(:,j));
end
Question: F
is the matrix that I would like to construct. However, step (3) is unfeasible due to the large r(1),..., r(28)
. Even a loop would take forever. Hence, I'm asking: is there a smarter way to construct F
that saves me from explicitly obtaining B
?
CodePudding user response:
Here is a fast solution (without using ndgrid
):
F = zeros(2,28);
mx = cellfun(@max,b)
mn = cellfun(@min,b)
for k = 1: 28
F(1,k) = min(b{k}-(b{k} sum(mx)-mx(k))/28);
F(2,k) = max(b{k}-(b{k} sum(mn)-mn(k))/28);
end
Explanation:
Suppose matrix B
to be:
B =
1 3 5
1 3 6
1 4 5
1 4 6
2 3 5
2 3 6
2 4 5
2 4 6
So we want to compute MinB=min(B-mean(B,2))
. There are 3 columns and MinB = [MinB(1) MinB(2) MinB(3)]
.
We begin to compute for the first column or MinB(1)
.
We can split the B
matrix based on the values of the first column :
B1=
1 3 5
1 3 6
1 4 5
1 4 6
B2=
2 3 5
2 3 6
2 4 5
2 4 6
so MinB(1)
can be computed as min(MinB1(1), MinB2(1))
.
And MinB1(1)
can be written as: MinB1(1) = min(1 - mean(B1, 2))
.
Equivalently is can be written as: MinB1(1) = 1 - max(mean(B1, 2))
.
We can write mean
as sum
: max(mean(B1, 2))== > max(sum(B1,2)/3)
.
Consider all combinations of numbers. Which combination has the maximum mean
or maximum sum
? the combination that contains max of each vector of b
or mx=[2 4 6]
.
So we have used cellfun
to compute max
for each vector of b
. This way we don't need to compute the mean of the all combinations we just need to compute max
for each vector of b
and then compute the mean of that vector.
That is the key point to the above solution and max
can also be computed this way.