Matrix to Diagonal Matrix in MATLAB [duplicate] - matlab

This question already has answers here:
How to vectorize row-wise diagonalization of a matrix
(4 answers)
Closed 9 years ago.
Let's say I have a matrix in MATLAB like
A = [1 2 3;
4 5 6;
7 8 9]
and I would like to obtain a matrix of the form
B = [1 0 0;
0 4 0;
0 0 7;
2 0 0;
0 5 0;
0 0 8;
3 0 0;
0 6 0;
0 0 9]
i.e. a matrix that is a concatenation of three diagonal matrices, with each having the columns of matrix A at their diagonals. I know how to do this using a for loop over the columns of A and then concatenating all the results but I am looking for a shorter way to do this. Please share your ideas.

B(repmat(eye(3),3,1)==1) = A;
reshape(B, [], 3)

Here's a way using linear indexing:
B(sub2ind([9 3], 1:9, mod(0:8,3)+1))=A;
reshape(B,9,3)
If you want this to be generic, realize that each column of the original becomes a diagonal. Therefore, the number of rows in the original becomes the number of columns in the output, and 3 rows x cols becomes the number of rows. The rest of the answer doesn't change at all:
c = size(A,1);
r = size(A,1) * size(A,2); #% or prod(size(A));
B(sub2ind([r c], 1:r, mod(0:(r-1),c)+1)) = A;

B = sparse( 1:numel(A), repmat( 1:size(A,2), [1 size(A,1)] ),...
A(:), numel(A), size(A,2));
should do the trick.
You can B = full(B); if you want a full matrix

Related

Matlab, 1 x M matrix from N x M matrix [duplicate]

This question already has answers here:
How to subtract a vector from each row of a matrix? [duplicate]
(2 answers)
Closed 7 years ago.
I'm trying to substract a 1 x M matrix from a N x M matrix.
lets say my 1 x M matrix is [1 2]
and my N x M matrix is [3 4; 5 4; 1 6]
and what I want as a result is [2 2; 4 2; 0 4]
I know how to do this with a for loop etc, what I'm trying to figure out is is there a math way of doing this in a single line?
Thanks.
You can use the repmat function to extend your 1xM matrix to NxM and then perform the subtraction.
>> M = [1 2];
>> N = [3 4; 5 4; 1 6];
>> N - repmat(M, length(N), 1)
ans =
2 2
4 2
0 4
Alternatively as pointed out by Divakar you can use
>> bsxfun(#minus, N, M)
ans =
2 2
4 2
0 4

Row-by-row comparison in MATLAB

I want to compare every row of a matrix with its every other row, element by element wise, using MATLAB. If two of the entries match, the result will be stored as 1, and if they don't match, it will be 0. This will give a symmetric matrix consisting of 0s and 1s.
For example, let A = [4 6 7 9 5; 2 6 9 9 1]
Then, the result expected is [1 1 1 1 1; 0 1 0 1 0; 0 1 0 1 0; 1 1 1 1 1]
The code I am using is (for a 1000*1000 random matrix):
A = randi(50,1000,1000);
B = zeros(1000000,1000);
D = zeros(1000000,1);
c=0;
for i=1:1000
for k=1:1000
for j=1:1000
if A(i,j)==A(k,j)
B(k+c,j)=1;
else
B(k+c,j)=0;
end
end
end
c=c+1000;
end
for l=1:1000000
D(l)=0;
for m=1:1000
D(l)=D(l)+(B(l,m)/(1000));
end
end
E=reshape(D,1000,1000);
This goes out of memory. Could anyone please suggest a solution or a more efficient code?
you can try row by row comparison directly as taking a complete row array and comparing with the other row array.
For example,
let
A = [4 6 7 9 5; 2 6 9 9 1];
nA = length(A(:,1));
finalMat = [];
for i = 1:nA
matRow = ones(nA,1)*A(i,:); % create a matrix size of A consists of same row elements
finalMat = [finalMat;matRow == A];
end
see if it is okay for you application.
You can use permute to align dimensions apprpriately and then bsxfun for the comparisons:
reshape(bsxfun(#eq, permute(A, [1 3 2]), permute(A, [3 1 2])), [], size(A,2))

How to vectorize row-wise diagonalization of a matrix

I have an n-by-m matrix that I want to convert to a mn-by-m matrix, with each m-by-m block of the result containing the diagonal of each row.
For example, if the input is:
[1 2; 3 4; 5 6]
the output should be:
[1 0; 0 2; 3 0; 0 4; 5 0; 0 6]
Of course, I don't want to assemble the matrix step by step myself with a for loop.
Is there a vectorized and simple way to achieve this?
For a vectorized way to do this, create the linear indices of the diagonal elements into the resulting matrix, and assign directly.
%# create some input data
inArray = [10 11;12 13;14 15];
%# make the index array
[nr,nc]=size(inArray);
idxArray = reshape(1:nr*nc,nc,nr)';
idxArray = bsxfun(#plus,idxArray,0:nr*nc:nr*nc^2-1);
%# create output
out = zeros(nr*nc,nc);
out(idxArray) = inArray(:);
out =
10 0
0 11
12 0
0 13
14 0
0 15
Here's a simple vectorized solution, assuming X is the input matrix:
Y = repmat(eye(size(X, 2)), size(X, 1), 1);
Y(find(Y)) = X;
Another alternative is to use sparse, and this can be written as a neat one-liner:
Y = full(sparse(1:numel(X), repmat(1:size(X, 2), 1, size(X, 1)), X'));
The easiest way I see to do this is actually quite simple, using simple index referencing and the reshape function:
I = [1 2; 3 4; 5 6];
J(:,[1,4]) = I;
K = reshape(J',2,6)';
If you examine J, it looks like this:
J =
1 0 0 2
3 0 0 4
5 0 0 6
Matrix K is just what wanted:
K =
1 0
0 2
3 0
0 4
5 0
0 6
As Eitan T has noted in the comments, the above is specific to the example, and doesn't cover the general solution. So below is the general solution, with m and n as described in the question.
J(:,1:(m+1):m^2) = I;
K=reshape(J',m,m*n)';
If you want to test it to see it working, just use
I=reshape(1:(m*n),m,n)';
Note: if J already exists, this can cause problems. In this case, you need to also use
J=zeros(n,m^2);
It may not be the most computationally efficient solution, but here's a 1-liner using kron:
A = [1 2; 3 4; 5 6];
B = diag(reshape(A', 6, 1) * kron(ones(3, 1), eye(2))
% B =
% 1 0
% 0 2
% 3 0
% 0 4
% 5 0
% 0 6
This can be generalized if A is n x m:
diag(reshape(A.', n*m, 1)) * kron(ones(n,1), eye(m))

Set column to 0 with probability p

I've got a matrix A with the dimensions m X n. For every column i (i > 0and i <= n) I want to flip a coin and fill the whole column with 0 values with probability p. How can this be accomplished in MATLAB?
Example:
A = [1 2 3 4; 5 6 7 8] and p = 0.5 could result in
A' = [1 0 3 0; 5 0 7 0]
You can use the function rand() to generate an array of uniformly distributed random numbers, and use logical indexing to select colums where that array is less than p:
A = [1 2 3 4; 5 6 7 8];
p = 0.5;
A(:, rand(size(A,2), 1)<p) = 0
A =
0 2 0 0
0 6 0 0
You can do something like bsxfun(#times, A, rand(1, size(A, 2)) > p). Alex's answer is admittedly better, though.

Matlab, Integer vector to binary matrix without loop [duplicate]

This question already has answers here:
Creating Indicator Matrix
(6 answers)
Closed 7 years ago.
I have a vector with N elements, all integers 1-M. I want to convert this to a NxM matrix with each row containing only zeros except for the i:th element set to one, i being the integer in the vector.
For example:
[1 1 3] => [1 0 0; 1 0 0; 0 0 1]
I currently do this in a loop, like this:
y_vec = zeros(m, num_labels);
for i = 1:m
y_vec(i, y(i)) = 1;
end
Is there a way to do this without a loop?
Yes, there is:
y = [1 1 3];
m = length(y);
num_labels = max(y);
%# initialize y_vec
y_vec = zeros(m,num_labels);
%# create a linear index from {row,y}
idx = sub2ind(size(y_vec),1:m,y);
%# set the proper elements of y_vec to 1
y_vec(idx) = 1;
If you have access to Statistics Toolbox, the command dummyvar does exactly this.
>> dummyvar([1 1 3])
ans =
1 0 0
1 0 0
0 0 1
(This has been asked in Creating Indicator Matrix and Matlab/Octave 1-of-K representation.)
My favorite answer is woodchips' sparse(1:n,labels,1,n,m);.