compare multiple matrices matlab - matlab

I have multiple matrices of the same size and want to compare them.
As a result I need a matrix which gives me the biggest of the 3 for every value.
I will clarify what i mean with an example:
I have 3 matrices with data of 3 persons.
I would like to compare these 3 and get a matrix as result.
In that matrix every cell/value should be the name of the matrix who had the highest value for that cell. So if in the 3 matrices the first value (1 colum, 1 row) is accordingly 2, 5, 8 the first value of the result matrix should be 3 (or the name of the 3 matrix).

If the three matrices are A, B, C, do this:
[~, M] = max(cat(3,A,B,C),[],3);
It creates a 3D "matrix" and maximizes across the third dimension.

Concatenate them on the 3rd dimension, and the use the SECOND output from max to get exactly what you want
A = rand(3,3);
B = rand(3,3);
C = rand(3,3);
D = cat(3, A, B, C)
[~, Solution] = max(D, [], 3)
e.g.:
D =
ans(:,:,1) =
0.70101 0.31706 0.83874
0.89421 0.33783 0.55681
0.68520 0.11697 0.45631
ans(:,:,2) =
0.268715 0.213200 0.124450
0.869847 0.999649 0.153353
0.345447 0.023523 0.338099
ans(:,:,3) =
0.216665 0.297900 0.604734
0.103340 0.767206 0.660668
0.127052 0.430861 0.021584
Solution =
1 1 1
1 2 3
1 3 1

edit
As I did not know about the second argument of the max-function, here is what you should NOT use:
old
Well, quick&dirty:
x=[2 5 8];
w=max(x)
[~,loc] = ismember(w,x)

Related

Using vector as indices not working as expected, matlab

Given a nXm matrix A and a mX2 matrix B and a matrix C of size mX1 containing 1s and 2s C=[1 2 1 2 1...], depending on which column, I want every row of A to be multiplied with. How can this be done? Or equivalently, given D = A*B how can I access only the values dictated by C. I tried D(:,C), but the result is not the expected.
Example a =[1 2; 3 4; 5 6] . c = [1 2 1] . a(?) = [1 4 5]
Any idea?
%example data
n=10;m=20;
A=rand(n,m)
B=rand(m,2)
C=round(rand(m,1))+1;
%solution:
B2=B(:,1); %multiplication vector
B2(C==2)=B(C==2,2) %change the ones where C==2
A*B2
You can run the following command for the last example:
a(sub2ind([3,2],1:3,c))'
In general case you can do like the following:
% n is the length of the D which is nx2 matrix
D(sub2ind([n,2],1:n,C))'

How to get all the possible combinations of elements in a matrix, but don't allow exchange of elements inbetween columns?

Lets say I have this matrice A: [3 x 4]
1 4 7 10
2 5 8 11
3 6 9 12
I want to permute the element of in each column, but they can't change to a different column, so 1 2 3 need to always be part of the first column. So for exemple I want:
3 4 8 10
1 5 7 11
2 6 9 12
3 4 8 11
1 6 7 10
2 5 9 12
1 6 9 11
. . . .
So in one matrix I would like to have all the possible permutation, in this case, there are 3 different choices 3x3x3x3=81possibilities.So my result matrixe should be 81x4, because I only need each time one [1x4]line vector answer, and that 81 time.
An other way to as the question would be (for the same end for me), would be, if I have 4 column vector:
a=[1;2;3]
b=[4;5;6]
c=[7;8;9]
d=[10;11;12;13]
Compare to my previous exemple, each column vector can have a different number of row. Then is like I have 4 boxes, A, B C, D and I can only put one element of a in A, b in B and so on; so I would like to get all the permutation possible with the answer [A B C D] beeing a [1x4] row, and in this case, I would have 3x3x3x4=108 different row. So where I have been missunderstood (my fault), is that I don't want all the different [3x4] matrix answers but just [1x4]lines.
so in this case the answer would be:
1 4 7 10
and 1 4 7 11
and 1 4 7 12
and 1 4 7 13
and 2 4 8 10
and ...
until there are the 108 combinations
The fonction perms in Matlab can't do that since I don't want to permute all the matrix (and btw, this is already a too big matrix to do so).
So do you have any idea how I could do this or is there is a fonction which can do that? I, off course, also could have matrix which have different size. Thank you
Basically you want to get all combinations of 4x the permutations of 1:3.
You could generate these with combvec from the Neural Networks Toolbox (like #brainkz did), or with permn from the File Exchange.
After that it's a matter of managing indices, applying sub2ind (with the correct column index) and rearranging until everything is in the order you want.
a = [1 4 7 10
2 5 8 11
3 6 9 12];
siz = size(a);
perm1 = perms(1:siz(1));
Nperm1 = size(perm1,1); % = factorial(siz(1))
perm2 = permn(1:Nperm1, siz(2) );
Nperm2 = size(perm2,1);
permidx = reshape(perm1(perm2,:)', [Nperm2 siz(1), siz(2)]); % reshape unnecessary, easier for debugging
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Nperm2*siz(1) ,1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Nperm2*siz(1) siz(2)]);
result = a(lin_idx);
This avoids any loops or cell concatenation and uses straigh indexing instead.
Permutations per column, unique rows
Same method:
siz = size(a);
permidx = permn(1:siz(1), siz(2) );
Npermidx = size(permidx, 1);
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Npermidx, 1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Npermidx siz(2)]);
result = a(lin_idx);
Your question appeared to be a very interesting brain-teaser. I suggest the following:
in = [1,2,3;4,5,6;7,8,9;10,11,12]';
b = perms(1:3);
a = 1:size(b,1);
c = combvec(a,a,a,a);
for k = 1:length(c(1,:))
out{k} = [in(b(c(1,k),:),1),in(b(c(2,k),:),2),in(b(c(3,k),:),3),in(b(c(4,k),:),4)];
end
%and if you want your result as an ordinary array:
out = vertcat(out{:});
b is a 6x3 array that contains all possible permutations of [1,2,3]. c is 4x1296 array that contains all possible combinations of elements in a = 1:6. In the for loop we use number from 1 to 6 to get the permutation in b, and that permutation is used as indices to the column.
Hope that helps
this is another octave friendly solution:
function result = Tuples(A)
[P,n]= size(A);
M = reshape(repmat(1:P, 1, P ^(n-1)), repmat(P, 1, n));
result = zeros(P^ n, n);
for i = 1:n
result(:, i) = A(reshape(permute(M, circshift((1:n)', i)), P ^ n, 1), i);
end
end
%%%example
A = [...
1 4 7 10;...
2 5 8 11;...
3 6 9 12];
result = Tuples(A)
Update:
Question updated that: given n vectors of different length generates a list of all possible tuples whose ith element is from vector i:
function result = Tuples( A)
if exist('repelem') ==0
repelem = #(v,n) repelems(v,[1:numel(v);n]);
end
n = numel(A);
siz = [ cell2mat(cellfun(#numel, A , 'UniformOutput', false))];
tot_prd = prod(siz);
cum_prd=cumprod(siz);
tot_cum = tot_prd ./ cum_prd;
cum_siz = cum_prd ./ siz;
result = zeros(tot_prd, n);
for i = 1: n
result(:, i) = repmat(repelem(A{i},repmat(tot_cum(i),1,siz(i))) ,1,cum_siz(i));
end
end
%%%%example
a = {...
[1;2;3],...
[4;5;6],...
[7;8;9],...
[10;11;12;13]...
};
result =Tuples(a)
This is a little complicated but it works without the need for any additional toolboxes:
You basically want a b element 'truth table' which you can generate like this (adapted from here) if you were applying it to each element:
[b, n] = size(A)
truthtable = dec2base(0:power(b,n)-1, b) - '0'
Now you need to convert the truth table to linear indexes by adding the column number times the total number of rows:
idx = bsxfun(#plus, b*(0:n-1)+1, truthtable)
now you instead of applying this truth table to each element you actually want to apply it to each permutation. There are 6 permutations so b becomes 6. The trick is to then create a 6-by-1 cell array where each element has a distinct permutation of [1,2,3] and then apply the truth table idea to that:
[m,n] = size(A);
b = factorial(m);
permutations = reshape(perms(1:m)',[],1);
permCell = mat2cell(permutations,ones(b,1)*m,1);
truthtable = dec2base(0:power(b,n)-1, b) - '0';
expandedTT = cell2mat(permCell(truthtable + 1));
idx = bsxfun(#plus, m*(0:n-1), expandedTT);
A(idx)
Another answer. Rather specific just to demonstrate the concept, but can easily be adapted.
A = [1,4,7,10;2,5,8,11;3,6,9,12];
P = perms(1:3)'
[X,Y,Z,W] = ndgrid(1:6,1:6,1:6,1:6);
You now have 1296 permutations. If you wanted to access, say, the 400th one:
Permutation_within_column = [P(:,X(400)), P(:,Y(400)), P(:,Z(400)), P(:,W(400))];
ColumnOffset = repmat([0:3]*3,[3,1])
My_permutation = Permutation_within_column + ColumnOffset; % results in valid linear indices
A(My_permutation)
This approach allows you to obtain the 400th permutation on demand; if you prefer to have all possible permutations concatenated in the 3rd dimension, (i.e. a 3x4x1296 matrix), you can either do this with a for loop, or simply adapt the above and vectorise; for example, if you wanted to create a 3x4x2 matrix holding the first two permutations along the 3rd dimension:
Permutations_within_columns = reshape(P(:,X(1:2)),3,1,[]);
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Y(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Z(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,W(1:2)),3,1,[]));
ColumnOffsets = repmat([0:3]*3,[3,1,2]);
My_permutations = Permutations_within_columns + ColumnOffsets;
A(My_permutations)
This approach enables you to collect a specific subrange, which may be useful if available memory is a concern (i.e. for larger matrices) and you'd prefer to perform your operations by blocks. If memory isn't a concern you can get all 1296 permutations at once in one giant matrix if you wish; just adapt as appropriate (e.g. replicate ColumnOffsets the right number of times in the 3rd dimension)

Shifting repeating rows to a new column in a matrix

I am working with a n x 1 matrix, A, that has repeating values inside it:
A = [0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4]
which correspond to an n x 1 matrix of B values:
B = [2;4;6;8;10; 3;5;7;9;11; 4;6;8;10;12; 5;7;9;11;13]
I am attempting to produce a generalised code to place each repetition into a separate column and store it into Aa and Bb, e.g.:
Aa = [0 0 0 0 Bb = [2 3 4 5
1 1 1 1 4 5 6 7
2 2 2 2 6 7 8 9
3 3 3 3 8 9 10 11
4 4 4 4] 10 11 12 13]
Essentially, each repetition from A and B needs to be copied into the next column and then deleted from the first column
So far I have managed to identify how many repetitions there are and copy the entire column over to the next column and then the next for the amount of repetitions there are but my method doesn't shift the matrix rows to columns as such.
clc;clf;close all
A = [0;1;2;3;4;0;1;2;3;4;0;1;2;3;4;0;1;2;3;4];
B = [2;4;6;8;10;3;5;7;9;11;4;6;8;10;12;5;7;9;11;13];
desiredCol = 1; %next column to go to
destinationCol = 0; %column to start on
n = length(A);
for i = 2:1:n-1
if A == 0;
A = [ A(:, 1:destinationCol)...
A(:, desiredCol+1:destinationCol)...
A(:, desiredCol)...
A(:, destinationCol+1:end) ];
end
end
A = [...] retrieved from Move a set of N-rows to another column in MATLAB
Any hints would be much appreciated. If you need further explanation, let me know!
Thanks!
Given our discussion in the comments, all you need is to use reshape which converts a matrix of known dimensions into an output matrix with specified dimensions provided that the number of elements match. You wish to transform a vector which has a set amount of repeating patterns into a matrix where each column has one of these repeating instances. reshape creates a matrix in column-major order where values are sampled column-wise and the matrix is populated this way. This is perfect for your situation.
Assuming that you already know how many "repeats" you're expecting, we call this An, you simply need to reshape your vector so that it has T = n / An rows where n is the length of the vector. Something like this will work.
n = numel(A); T = n / An;
Aa = reshape(A, T, []);
Bb = reshape(B, T, []);
The third parameter has empty braces and this tells MATLAB to infer how many columns there will be given that there are T rows. Technically, this would simply be An columns but it's nice to show you how flexible MATLAB can be.
If you say you already know the repeated subvector, and the number of times it repeats then it is relatively straight forward:
First make your new A matrix with the repmat function.
Then remap your B vector to the same size as you new A matrix
% Given that you already have the repeated subvector Asub, and the number
% of times it repeats; An:
Asub = [0;1;2;3;4];
An = 4;
lengthAsub = length(Asub);
Anew = repmat(Asub, [1,An]);
% If you can assume that the number of elements in B is equal to the number
% of elements in A:
numberColumns = size(Anew, 2);
newB = zeros(size(Anew));
for i = 1:numberColumns
indexStart = (i-1) * lengthAsub + 1;
indexEnd = indexStart + An;
newB(:,i) = B(indexStart:indexEnd);
end
If you don't know what is in your original A vector, but you do know it is repetitive, if you assume that the pattern has no repeats you can use the find function to find when the first element is repeated:
lengthAsub = find(A(2:end) == A(1), 1);
Asub = A(1:lengthAsub);
An = length(A) / lengthAsub
Hopefully this fits in with your data: the only reason it would not is if your subvector within A is a pattern which does not have unique numbers, such as:
A = [0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0;]
It is worth noting that from the above intuitively you would have lengthAsub = find(A(2:end) == A(1), 1) - 1;, But this is not necessary because you are already effectively taking the one off by only looking in the matrix A(2:end).

access cell array by two vector not pairwise

If I have a Cell array 2*2 where A{i,j} is a matrix, and I have two vectors v=1:2,c=1:2.
I want A(v,c) to return only A{1,1} and A{2,2} but matlab returns every combination of the two(aka also returns A{1,2} and A{2,1}).
Is there a way without using loops or cellfun ?
What I suspect you are doing is something like this:
B = A(v, c);
When you specify vectors to index into A, it finds the intersection of coordinates and gives you those elements. As such, with your indexing you are basically returning all of the elements in A.
If you want just the top left and lower right elements, use sub2ind instead. You can grab the column-major indices of those locations in your cell array, then slice into your cell array with these indices:
ind = sub2ind(size(A), v, c);
B = A(ind);
Example
Let's create a sample 2 x 2 cell array:
A = cell(2,2);
A{1,1} = ones(2);
A{1,2} = 2*ones(2);
A{2,1} = 3*ones(2);
A{2,2} = 4*ones(2);
Row 1, column 1 is a 2 x 2 matrix of all 1s. Row 1, column 2 is a 2 x 2 matrix of 2s, row 2 column 1 is a 2 x 2 matrix of all 3s and the last entry is a 2 x 2 matrix of all 4s.
With v = 1:2; c=1:2;, running the above code gives us:
>> celldisp(B)
B{1} =
1 1
1 1
B{2} =
4 4
4 4
As you can see, we picked out the top left and bottom right entries exactly.
Minor Note
If it's seriously just a cell array of 2 x 2, and you only want to pick out the top left and lower right elements, you can just do:
B = A([1 4]);
sub2ind would equivalently return 1 and 4 as the column major indices for the top left and lower right elements. This avoids the sub2ind call and still achieves what you want.

combine two n dimensional cell arrays into a n by n dimensional one

I wonder how to do this in MATLAB.
I have a={1;2;3} and would like to create a cell array
{{1,1};{1,2};{1,3};{2,1};{2,2};{2,3};{3,1};{3,2};{3,3}}.
How can I do this without a for loop?
You can use allcomb from MATLAB File-exchange to help you with this -
mat2cell(allcomb(a,a),ones(1,numel(a)^2),2)
Just for fun, using kron and repmat:
a = {1;2;3}
b = mat2cell([kron(cell2mat(a),ones(numel(a),1)) repmat(cell2mat(a),numel(a),1)])
Here square brackets [] are used to perform a concatenation of both column vectors, where each is defined either by kron or repmat.
This can be easily generalized, but I doubt this is the most efficient/fast solution.
Using repmat and mat2cell
A = {1;2;3};
T1 = repmat(A',[length(A) 1]);
T2 = repmat(A,[1 length(A)]);
C = mat2cell(cell2mat([T1(:),T2(:)]),ones(length(T1(:)),1),2);
You can use meshgrid to help create unique permutations of pairs of values in a by unrolling both matrix outputs of meshgrid such that they fit into a N x 2 matrix. Once you do this, you can determine the final result using mat2cell to create your 2D cell array. In other words:
a = {1;2;3};
[x,y] = meshgrid([a{:}], [a{:}]);
b = mat2cell([x(:) y(:)], ones(numel(a)*numel(a),1), 2);
b will contain your 2D cell array. To see what's going on at each step, this is what the output of the second line looks like. x and y are actually 2D matrices, but I'm going to unroll them and display what they both are in a matrix where I've concatenated both together:
>> disp([x(:) y(:)])
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Concatenating both vectors together into a 2D matrix is important for the next line of code. This is a vital step in order to achieve what you want. After the second line of code, the goal will be to make each element of this concatenated matrix into an individual cell in a cell array, which is what mat2cell is doing in the end. By running this last line of code, then displaying the contents of b, this is what we get:
>> format compact;
>> celldisp(b)
b{1} =
1 1
b{2} =
1 2
b{3} =
1 3
b{4} =
2 1
b{5} =
2 2
b{6} =
2 3
b{7} =
3 1
b{8} =
3 2
b{9} =
3 3
b will be a 9 element cell array and within each cell is another cell array that is 1 x 2 which stores one row of the concatenated matrix as individual cells.