Combining columns of two matrices of different dimension in Matlab? - matlab

I have a matrix in Matlab A of dimension nx3, e.g. n=8
A=[ 0.3 2 2;
0.3 7 7;
0.3 10 10;
0 15 15;
0.3 18 2;
0.3 23 7;
0 26 10;
0.3 31 15]
and a matrix B of dimension mx4, e.g. m=17
B=[1 1 0.05 0.05;
2 2 0.22 0.22;
3 3 0.19 0.05;
5 5 0.02 0.02;
6 6 0.19 0 ;
7 7 0.30 0.11;
10 10 0.27 0.08;
11 11 0.19 0 ;
12 12 0.05 0.05;
18 2 0.25 0.08;
19 3 0.25 0.08;
21 5 0.02 0.02;
22 6 0.22 0.08;
23 7 0.22 0.08;
30 14 0.19 0.08;
31 15 0.19 0.08;
32 16 0.05 0.05]
I want to create a matrix C following these steps WITHOUT USING LOOPS:
1) Generate C=[];
2) Consider B(i,1). If there exists A(j,2)=B(i,1) [it can happen only once] report C=[ C; B(i,1) B(i,2) B(i,3) B(i,4) A(i,1)]. Do this for i=1,...,m.
3) Consider B(h,1) such that there is no j with A(j,2)=B(h,1). Report C=[C; B(h,1) B(h,2) B(h,3) B(h,4) 0]. Do this for h=1,...,m.
4) Consider A(h,2) such that there is no j with B(j,1)=A(h,2). Report C=[C; A(h,2) A(h,3) 0 0 A(h,1)]. Do this for h=1,...,n.
In the example above I want to get
C=[2 2 0.22 0.22 0.3;
7 7 0.30 0.11 0.3;
10 10 0.27 0.08 0.3;
18 2 0.25 0.08 0.3;
23 7 0.22 0.08 0.3;
31 15 0.19 0.08 0.3; %end step 2)
---------------------
1 1 0.05 0.05 0 ;
3 3 0.19 0.05 0 ;
5 5 0.02 0.02 0 ;
6 6 0.19 0 0 ;
11 11 0.19 0 0 ;
12 12 0.05 0.05 0 ;
19 3 0.25 0.08 0 ;
21 5 0.02 0.02 0 ;
22 6 0.22 0.08 0 ;
30 14 0.19 0.08 0 ;
32 16 0.05 0.05 0 ;
----------------------- %end step 3)
15 15 0 0 0 ;
26 10 0 0 0 ] %end step 4)
These code does what I want but it is too slow with bigger matrices
C=[];
%Step 1)
for l=1:size(B,1)
for h=1:size(A,1)
if B(l,1)==A(h,2)
C=[C; B(l,:) A(h,1)];
end
end
end
% Steps 2) and 3)
C=[C; ...
[B(logical(1-ismember(B(:,1), A(:,2))),:) zeros(size(B(logical(1-ismember(B(:,1), A(:,2))),:),1),1)];...
[A(logical(1-ismember(A(:,2), B(:,1))),2:3) ...
zeros(size(A(logical(1-ismember(A(:,2), B(:,1)))),1),2) ...
A(logical(1-ismember(A(:,2), B(:,1))),1)]];

Although it smells strongly like homework, here is some code. See it as a tutorial on matrix operations (tested with Octave).
% Step 1
[~,j,k] = intersect(B(:,1),A(:,2));
C = [B(j,:) A(k,1)];
% Step 2
[~,k] = setdiff(B(:,1),A(:,2));
C = [C; B(k,:) zeros(size(k,1),1)]
% Step 3
[~,k] = setdiff(A(:,2),B(:,1));
C = [C; A(k,[2 3]) zeros(size(k,1),2) A(k,1)]
C =
2.00000 2.00000 0.22000 0.22000 0.30000
7.00000 7.00000 0.30000 0.11000 0.30000
10.00000 10.00000 0.27000 0.08000 0.30000
18.00000 2.00000 0.25000 0.08000 0.30000
23.00000 7.00000 0.22000 0.08000 0.30000
31.00000 15.00000 0.19000 0.08000 0.30000
1.00000 1.00000 0.05000 0.05000 0.00000
3.00000 3.00000 0.19000 0.05000 0.00000
5.00000 5.00000 0.02000 0.02000 0.00000
6.00000 6.00000 0.19000 0.00000 0.00000
11.00000 11.00000 0.19000 0.00000 0.00000
12.00000 12.00000 0.05000 0.05000 0.00000
19.00000 3.00000 0.25000 0.08000 0.00000
21.00000 5.00000 0.02000 0.02000 0.00000
22.00000 6.00000 0.22000 0.08000 0.00000
30.00000 14.00000 0.19000 0.08000 0.00000
32.00000 16.00000 0.05000 0.05000 0.00000
15.00000 15.00000 0.00000 0.00000 0.00000
26.00000 10.00000 0.00000 0.00000 0.00000

Related

Remove zeros from a matrix

I have a matrix with large rows and columns as follows:
A = 0 0 0 0
0 0 0 0
0 0 0 0
2000 11 16 -0.74
0 0 0 0
0 0 0 0
2000 12 26 -0.84
0 0 0 0
0 0 0 0
I need to remove all the zeros from the matrix to get output like,
B = 2000 11 16 -0.74
2000 12 26 -0.84
I have tried an available solution over here like,
B = A(A~=0)
It removes zeros but gives output like,
2000
2000
11
12
-0.74
-0.84
How to get the desired output?
assuming A is a two dimensional matrix
A(any(A,2),:)
will do.
Example:
>> A=[rand(2,3); zeros(3); rand(1,3)]
A =
0.13878 0.44315 0.25832
0.01879 0.93844 0.57537
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000
0.50581 0.37870 0.56563
>> A(any(A,2),:)
ans =
0.138776 0.443152 0.258325
0.018794 0.938439 0.575371
0.505809 0.378696 0.565632

Split a vector into smaller vectors in matlab

Are there any efficient way to do the following?
I have this vector:
0.923
0.757
0.552
0.298
0.079
0.925
0.769
0.565
0.297
0.075
0.927
0.777
0.572
0.294
0.072
0.931
0.778
0.57
0.292
0.07
0.933
0.78
0.566
0.293
0.075
I want to split this vector to smaller vectors each one consist of 5 values, and adding 1 in the top and 0 at the end of each vector
like this:
1
0.923
0.757
0.552
0.298
0.079
0
1
0.925
0.769
0.565
0.297
0.075
0
1
0.927
0.777
0.572
0.294
0.072
0
1
0.931
0.778
0.57
0.292
0.07
0
1
0.933
0.78
0.566
0.293
0.075
0
can I use cumsum to find the difference between value 1 and 2 in the same vector ?
for example, the first vector
0.923 - 1 = 0.077
and form another vector with the answers ?
v =[0.923
0.757
0.552
0.298
0.079
0.925
0.769
0.565
0.297
0.075
0.927
0.777
0.572
0.294
0.072
0.931
0.778
0.57
0.292
0.07
0.933
0.78
0.566
0.293
0.075];
A = reshape(v,5,[]);
A = [ones(1,size(A,2)) ; A ; zeros(1,size(A,2))]
A =
1.00000 1.00000 1.00000 1.00000 1.00000
0.92300 0.92500 0.92700 0.93100 0.93300
0.75700 0.76900 0.77700 0.77800 0.78000
0.55200 0.56500 0.57200 0.57000 0.56600
0.29800 0.29700 0.29400 0.29200 0.29300
0.07900 0.07500 0.07200 0.07000 0.07500
0.00000 0.00000 0.00000 0.00000 0.00000
B = diff(A)
B =
-0.077000 -0.075000 -0.073000 -0.069000 -0.067000
-0.166000 -0.156000 -0.150000 -0.153000 -0.153000
-0.205000 -0.204000 -0.205000 -0.208000 -0.214000
-0.254000 -0.268000 -0.278000 -0.278000 -0.273000
-0.219000 -0.222000 -0.222000 -0.222000 -0.218000
-0.079000 -0.075000 -0.072000 -0.070000 -0.075000

Changing diagonal values if equal to 1

I want to change the diagonal values if equal to 1.
is it possible to look for diagonals and change the values in this particular diagonal to another value.
For example:
X =
1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1
I want to change this diagonal :
1
0
1
to
2.2
0
2.2
I tried:
XX(logical(eye(size(XX)))) = 2
but this will change all the values not only ones.
Could you please explain how to do that for other diagonals?
The function diag is useful to manipulate diagonals. It only extracts a diagonal from a matrix, or forms a new matrix given a vector of diagonal elements. But with appropriate arithmetic this is sufficient:
X = [1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1];
k = 2; % which diagonal to change
d = diag(X,k); % the old diagonal
n = d;
n(n==1) = 2.2; % the new diagonal values
X = X - diag(d,k) + diag(n,k); % subtract old values from diagonal, add new ones
Output:
X =
1.00000 1.00000 2.20000 0.00000
1.00000 1.00000 0.00000 2.20000
1.00000 0.00000 1.00000 1.00000
0.00000 1.00000 1.00000 1.00000
Here comes a solution only using linear indexing. I wanted to avoid generating additional matrices. Nothing's wrong with Cris Luengo's answer, that was just for fun.
% Input.
X = [1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1]
% Which diagonal to change.
k = 2;
% Determine dimension.
dim = size(X, 1);
% Calculate indices of diagonal elements.
idx = (max(abs(k), k * dim) + 1):(dim + 1):numel(X);
idx = idx(1:end+min(k+1, 0));
% Replace diagonal elements with new value.
X(idx(X(idx) == 1)) = 2.2
Output:
X =
1.00000 1.00000 2.20000 0.00000
1.00000 1.00000 0.00000 2.20000
1.00000 0.00000 1.00000 1.00000
0.00000 1.00000 1.00000 1.00000

Matlab: Finding distance to nearest TRUE value in a matrix

Lets assume I have a logical matrix A (about 1000x1000 size) and want to find for each element the euclidean distance to the nearest TRUE value. How can that be done fast in Matlab?
E.g if i have matrix A:
A = [1 0 0 0
0 1 1 1
0 0 0 0
0 0 1 0]
Then what i want is:
B = [0 1 1 1
1 0 0 0
1.41 1 1 1
2 1 0 1]
One possibility would be imdilate(), but then i would have to dilate a MxN Matrix with a 2Mx2N Matrix, which would take way too long.
I tried calculating the distances from each element to each element==1 using pdist2() and then taking the minimum but that turned out to use way too much memory.
Any suggestions? I would also settle for a solution that just approximates it.
The bwdist function in the Image Processing Toolbox does precisely this
A = [1 0 0 0
0 1 1 1
0 0 0 0
0 0 1 0];
B = bwdist(A);
% 0.00000 1.00000 1.00000 1.00000
% 1.00000 0.00000 0.00000 0.00000
% 1.41421 1.00000 1.00000 1.00000
% 2.00000 1.00000 0.00000 1.00000

How do you create a 3d array which increase the value with each layer in Matlab?

i.e, a 3d matrix where all the values on each layer are the same, but the value on each sheet increments as the layers are increased.
The increment could be defined by x = (0:0.5:2*pi), for example.
I've tried using repmat, but this only seems to produce the matrix in another orientation.
Thanks!
One more possibility: use ndgrid, used here to create a 4-by-5-by-#x array:
x = 0:0.5:2*pi;
[~,~,out] = ndgrid(1:4,1:5,x);
You can do this using repmat and permute:
x = (0:0.5:2*pi);
y = repmat(x',[1,5,5]);
z = permute(y,[2,3,1]);
size(z)
ans =
5 5 13
z(:,:,1)
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
z(:,:,2)
ans =
0.50000 0.50000 0.50000 0.50000 0.50000
0.50000 0.50000 0.50000 0.50000 0.50000
0.50000 0.50000 0.50000 0.50000 0.50000
0.50000 0.50000 0.50000 0.50000 0.50000
0.50000 0.50000 0.50000 0.50000 0.50000
Define x
x = (0:0.5:2*pi);
This will have the values varying along the row (2nd dimension). Change your x to vary along the dimension you want (3rd dimension):
x = permute(x, [1, 3, 2]);
then repmat it:
x = repmat(x, [3, 3, 1]);