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.
Related
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).
I want data to be processed as follows.
Eg.
say data x(i)=[1 2 3 5 2 1].
Comparisons should be elements INDEX [1 to 2, 1 to 3, 1 to 4, 1 to 5, 1 to 6, 2 to 3,2 to 4,2 to 5,2 to 6,3 to 4....]
following the above logic
hence elements values of distance = [1, 2 , 3 , 4 , 5 , 1 , 2, 3, 4, 1, 2, 3, 1, 2, 1].
hence elements values of difference = [1, 2 , 4 , 1 , 0 , 1 , 3, 0, 1, 2, 1, 2, 3, 4, 1].
I have written the following code for the same but i notice that the final matrix 'b' that i want is always changing size when it should be constant. I welcome any suggestions
clc;
close all;
clear all;
% read data set
I= imread('img2.bmp');
G=double(rgb2gray(I));
%choose 2 random numbers
n = 1;
s = [1 960];
k = round(rand(n,1)*range(s)+min(s));
for i = 1:length(k)
% choose a particular row from a matrix
row_no=k(i);
%G=R(row_no,:);
% compare every element with its neigbour to create distance and difference matrix
x1=row_no;
x2=row_no;
for y1 = 1:length(G)%size(G,2)
for y2 =1:length(G) %1:size(G,2)
distance_Mat(y1,y2) = round(sqrt((y2-y1)^2 + (x2-x1)^2));
difference_Mat(y1,y2) = 1*(G(x1,y1) - G(x2,y2))^2;
end
end
%% now remove repeating comparisons
b=horzcat(distance_Mat(:),(difference_Mat(:)));
[UniXY,Index]=unique(b,'rows');
DupIndex=setdiff(1:size(b,1),Index);
b(DupIndex,:)=[];
%calculate the cumulative sums and store it in different colums of data matrix
A1 = cumsum(b);
data(:,1)=A1;
end
If you have the stats toolbox then
distance_Mat = squareform(pdist(x'));
only does each comparison once and then mirrors the data. You can get just the lower half by
tril(distance_Mat,-1);
If you don't have the toolbox then try this:
I = tril(ones(numel(x)),-1);
[r,c] = find(I);
distance_Mat = zeros(numel(x));
distance_Mat(logical(I)) = round(sqrt((x(r)-x(c)).^2)
Not sure even if this question stands valid. But better ask.
Suppose we have two matrices in MATLAB of size (n,1) and (m,1) and we want to copy certain rows from matrix A to matrix B on a condition.
e.g. if value A(i,1) is less or equal to X
And later delete those rows from source matrix i.e. matrix A
Example:
A = [1, 2, 3, 4, 5, 6]
B = [8, 9]
copy all values which are less than or equal to 4 from A to B, and delete from A
Matrices becomes
A = [5, 6]
B = [8, 9, 1, 2, 3, 4]
You can use a logical matrix to identify the items:
mask = (A <= 4);
B = [B A(mask)];
A(mask) = [];
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.
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.