Intersection of matrices in matlab? - matlab

It is almost the same question as this one Matrices intersection!
The difference is this: If the intersection of the element (i, j) of all matrices is the same number then do not output -1 but output this number. An example is the following:
A1 = [2, 2, 0;
2, 2, 0;
0, 2, 0];
A2 = [2, 0, 4;
4, 3, 0;
0, 0, 1];
A3 = [2, 0, 0;
1, 0, 3;
3, 4, 3];
I want to get the follow matrix:
B = [2, 2, 4;
-1, -1, 3;
3, -1, -1];

Version 1
out1 = -1.*(A1~=A2).*(A1~=A3).*(A2~=A3)
max_mat = max(cat(3,A1,A2,A3),[],3)
out1(~out1) = max_mat(~out1)
Output
out1 =
2 2 4
-1 -1 3
3 -1 -1
Version 2: Maybe a faster version
Assumption - If out of the three elements in the corresponding positions across A1, A2 and A3, only two are same, then take the max of those three elements for the final matrix, B.
Code
%%// Concatenate all three A matrices
A=cat(3,A1,A2,A3,A1);
%%// Logical matrix with ones where all three elements are different from each other
out1 = -1.*all(diff(A,[],3)~=0,3)
%%// Get the max values, to be stored where -1 all three corresponding elements
%%// are not different from each other
max_mat = max(A,[],3)
%%// Get the final output
out1(~out1) = max_mat(~out1)
This produces the same output as the previous version.
Version 3
Assumption - If out of the three elements in the corresponding positions across A1, A2 and A3, only two are same, then take the element that is different from the other two for the final matrix, B.
Code
A=cat(3,A1,A2,A3,A1);
AA = A(:,:,1:3);
t1 = bsxfun(#ne,AA,mode(AA,3));
out1 = max(AA.*t1,[],3) + all(~t1,3).*A1;
out1(all(diff(A,[],3)~=0,3))=-1;
This produces the same output as the previous versions.

I would do this
A = A1+A2+A3;
B = (A1==A2)&(A1==A3);
C = (A1==0)+(A2==0)+(A3==0);
D = ones(3)*-1;
D(B==1) = A1(B==1);
D(C==2) = A(C==2);
B records the position of the elements whose number is same for all the matrices.
C records the position of the elements where two of the matrices have 0.
Then we can modify the elements of D, whose values are set -1 initially, using the information in matrices B and C.

A1 = [2, 2, 0;
2, 2, 0;
0, 2, 0];
A2 = [2, 0, 4;
4, 3, 0;
0, 0, 1];
A3 = [2, 0, 0;
1, 0, 3;
3, 4, 3];
A=cat(3,A1,A2,A3);
%identify all fields with identical values on the 3rd dimension
[X,Y]=find(sum(abs(diff(A,1,3)),3)==0);
%delete all but the first repetition, then use the previous code
A(X,Y,2:end)=0;
L=(sum(A~=0,3)>1);
L*-1+(1-L).*sum(A,3)
/update: Had to fix the code, now it should be correct.

Related

MATLAB replacing certain values of matrix with another matrix

I have an arbitrary matrix, a = [1, 0, 0, 1].
I want to replace every 0 value with the values of another matrix b = [1, 2, 3], and every 1 value with the value of yet another matrix c = [3, 4, 5].
I would therefore end up with the matrix [3, 4, 5, 1, 2, 3, 1, 2, 3, 3, 4, 5].
I've tried finding the indices of the 0 and 1 values and replacing the values at those indices with b and c, but this isn't allowed since they aren't the same size. Is there any simple way of achieving this?
Given
a = [1, 0, 0, 1];
b = [1, 2, 3];
c = [3, 4, 5];
Let's first take the arrays we want in the final matrix and put them in a cell array:
parts = {b, c}
parts =
{
[1,1] =
1 2 3
[1,2] =
3 4 5
}
The goal is to use the values of a as indices into parts, but to do that we need all of the values to be positive from 1 to some n (if there are missing values it'll take a bit more work). In this case we can just increment a:
a_inds = a + 1
a_inds =
2 1 1 2
Now we can get a new cell array by doing parts(a_inds), or a matrix by adding cell2mat:
result = cell2mat(parts(a_inds))
result =
3 4 5 1 2 3 1 2 3 3 4 5
This can also be done with a key:value map.
a = [1, 0, 0, 1];
b = [1, 2, 3];
c = [3, 4, 5];
keyset = [1,0];
valueset = {b,c};
mapobj = containers.Map(keyset,valueset);
new_vec = [];
for i =1:length(a)
new_vec(length(new_vec)+1:length(new_vec)+length(mapobj(a(i))))= mapobj(a(i));
end
1 is mapped to b and 0 mapped to c. The for loop iterates over a building an ever longer vector containing the mapped values.
This code will allow for non-sequential keys such that 37 could be added and mapped to another vector, whereas in the previous answer you would have to map 2 to the next vector in order for the code not to break.

How to extract values from a Matrix that recorded in a vector?

Just came across this problem might be interesting in many applications, for example,
I have a vector A = [2; 5; 10], the values in vector A is sorted and unique.
I have got a matrix (2D or 3D), for example, B = [2, 8, 10; 2, 5, 5; 9, 1, 10];
Want to get a matrix C = [1, 0, 1; 1, 1, 1; 0, 0, 1].
It means if the element in B is also an element of A, we set it to one; otherwise, set the value to zero.
I did this in a for-loop, but for a large 3D matrix, it takes a long time to finish the loop.
Just wondering if there is a smarter method to do this without 'for' loop.
C = zeros(size(B));
for i = 1:size(A,1)
a = A(i);
C(B==a) = 1;
end
This is exactly what ismember does:
A = [2; 5; 10];
B = [2, 8, 10; 2, 5, 5; 9, 1, 10];
C = ismember(B,A)
C =
1 0 1
1 1 1
0 0 1
From the documentation:
ismember(A,B) returns an array containing 1 (true) where the data in A
is found in B. Elsewhere, it returns 0 (false).

Create a matrix according to a binary matrix

Here I got
A = [1, 2, 3]
B = [1, 0, 0, 1, 0, 1]
I want to create a matrix
C = [1, 0, 0, 2, 0, 3]
You can see B is like a mask, The number of ones in B is equal to the number of elements in A. What I want is arrange elements in A to the place where B is 1.
Any method without loop?
Untested, but should be close:
C = zeros(size(B));
C(logical(B)) = A;
This relies on logical indexing.

How to intersect two or more matrices?

Let say I have some number of matrices with non-negative entries, N matrices for example of equal sizes MxM. For example, I have 3 matrices as follow:
A1=[2, 2, 0;
2, 2, 0;
0, 2, 0];
A2=[4, 0, 4;
4, 3, 0;
0, 0, 1];
A3=[2, 0, 0;
1, 0, 3;
3, 4, 3];
I want to find the intersection of A1, A2, and A3 in matlab. That means I want to get the follow matrix:
B=[-1, 2, 4;
-1, -1, 3;
3, -1, -1];
If the intersection of the (i, j) element of the N matrices, i.e., the elements A1(i, j), A2(i, j), A3(i, j), is at most one nonzero number then B(i,j) equals that number. Else if the intersection is at least two numbers I output -1 as I showed in the previous example.
How can I do this in matlab without loops?
First, concatenate to a single 3D-Matrix:
A=cat(3,A1,A2,A3)
Then count the non-zero elements, which gives the location of the -1-Elements:
L=(sum(A~=0,3)>1)
Finally, There where L=1 we want a -1, otherwise we want the single element at that location, which is the sum because the others are zero:
L*-1+(1-L).*sum(A,3)
I would do it something like so:
First, count up the non-zero elements at each location across all matrices:
foo = (A1 ~= 0) + (A2 ~= 0) + (A3 ~= 0);
Next, find those which have more than one non-zero element, and set them to -1 in the result:
B = zeros(3,3);
B(foo > 1) = -1;
Finally, find the non-zero elements (since in the elements we care about there is only one non-zero element, this is the same as the sum across matrices)
sumA = A1 + A2 + A3;
And add them into the result matrix
B(foo == 1) = sumA(foo == 1);

Find the most repeated row in a MATLAB matrix

I am looking for a function to find the most repeated (i.e. modal) rows of a matrix in MATLAB. Something like:
>> A = [0, 1; 2, 3; 0, 1; 3, 4]
A =
0 1
2 3
0 1
3 4
Then running:
>> mode(A, 'rows')
would return [0, 1], ideally with a second output giving the indexes where this row occurred (i.e. [1, 3]'.)
Does anyone know of such a function?
You can use UNIQUE to get unique row indices, and then call MODE on them.
[uA,~,uIdx] = unique(A,'rows');
modeIdx = mode(uIdx);
modeRow = uA(modeIdx,:) %# the first output argument
whereIdx = find(uIdx==modeIdx) %# the second output argument
The answer may not be right. Try A = [2, 3; 0, 1; 3, 4; 0, 1].
It should be the following:
[a, b, uIdx] = unique(A,'rows');
modeIdx = mode(uIdx);
modeRow = a(modeIdx,:) %# the first output argument
whereIdx = find(ismember(A, modeRow, 'rows')) %# the second output argument