Transform vector with repeating values into a matrix in Matlab - matlab

I have a vector of n size, which I would like to transform into the Boolean matrix of nxm, where m is a number of unique values in that vector.
a = repmat(1:5:20,1,3)
a =
1 6 11 16 1 6 11 16 1 6 11 16
The result I would like to have is the matrix 12x4:
1 0 0 0
0 1 0 0
0 0 1 0
...
0 0 0 1
Any ideas how to do that without for loop?

You can try this:
a = repmat(1:5:20,1,3);
b = unique(a);
bsxfun(#eq, a', b)
The result would be:
ans =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

a = repmat(1:5:20,1,3)
b=unique(a);
c = repmat(a',1,numel(b))== repmat(b,numel(a),1);
but in general a loop will be faster, repmat is to be avoided.
So, now with a loop:
a = repmat(1:5:20,1,3)
b=unique(a);
c=false(numel(a),numel(b));
for ii=1:numel(a)
c(ii,:) = a(ii)==b;
end

Related

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

Extract multiple indices from matrix

I want to access multiple indices of a matrix as shown below. So what I want is indices (1,3),(2,6),(3,7) to be set to one. However, as you can see the entire column is set to one. I can see what it is doing but is there a way to do what I want it to (in an elegant way - no loops).
a=zeros(3,10)
a(1:3,[3 6 7])=1
a =
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
I realise that you can do something along the lines of
x_idx=1:3, y_idx=[3 6 7];
idx=x_idx*size(a,2)+y_idx;
a(idx)=1;
but just wondering if there was a better, or proper way of doing this in Matlab
You can use sub2ind, which essentially is doing what you have mentioned in your post, but MATLAB has this built-in:
a = zeros(3,10);
a(sub2ind(size(a), 1:3, [3 6 7])) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
Another way would be to create a logical sparse matrix, then use this to index into a:
a = zeros(3,10);
ind = logical(sparse(1:3, [3 6 7], true, size(a,1), size(a,2)));
a(ind) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0

matlab encoding integers to matrix of vectors of 0's and 1's [duplicate]

This question already has answers here:
Creating Indicator Matrix
(6 answers)
Closed 8 years ago.
I have a 1118x1 vector of values from 0 to 10 as such:
5
5
3
4
7
4
1
.
.
I need to encode each value into a 11x1118 Matrix of zeros where the k+1th values is a 1.
For example the first value is a 5 so the 5+1=6 value in the first column with be 1
0
0
0
0
0
1
0
0
0
0
0
I need to do this for all values up to 1118.
I assume I just need a for loop but am completely lost as to how to do it
You can use for example sub2ind. Try the following code:
x = [4;3;1;1;4;7];
y = zeros(11,numel(x));
y(sub2ind(size(y),x+1,(1:numel(x))')) = 1
y =
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 1 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Or a direct approach using loop:
v = [5 5 3 4 7 4 1...]; # your vector
M = zeros(11, length(v)); # the final matrix
for i = 1:length(v)
e = v(i);
M(e + 1, i) = 1;
end

matlab: how to create matrix by shift vector

I have row and column in matlab:
a = [1 0 3 ... a_k]; - row 1xk
b = [1;0;3; ... b_k]; - column kx1
I want to create new matrix's (A and B) mxn, that can be populate by shift row and column:
A = [1 0 3 0 0 0 0 ... 0;
0 1 0 3 0 0 0 ... 0;
0 0 1 0 3 0 0 ... 0;
...
0 0 0 0 0 0 ... 1 0 3 ]
B= [1 0 0 0 0 0 0 ... 0;
0 1 0 0 0 0 0 ... 0;
3 0 1 0 0 0 0 ... 0;
0 3 0 1 0 0 0 ... 0;
0 0 3 0 1 0 0 ... 0;
...
0 0 0 0 0 0 0 ... 3]
How can I do it?
Is this what you want?
>> a = [1 0 3];
>> m = 5; %// number of rows
>> A = convmtx(a,m)
A =
1 0 3 0 0 0 0
0 1 0 3 0 0 0
0 0 1 0 3 0 0
0 0 0 1 0 3 0
0 0 0 0 1 0 3
>> b = [1;0;3];
>> m = 4; %// number of columns
>> B = convmtx(b,m)
B =
1 0 0 0
0 1 0 0
3 0 1 0
0 3 0 1
0 0 3 0
0 0 0 3
You can do this in a slightly tricky way by using a combination of indexing and bsxfun. First we want to create an index matrix that represents the shift that we're trying to. It should look like this (at least for A):
1 2 3 4 ... k
k 1 2 3 ... k-1
etc
To create this, we can use bsxfun as follows:
index = mod(bsxfun(#plus,1:k,-(1:(k-2))'),k)+1;
We can then create the matrix A by using this as an index matrix for a:
A = a(index);
The matrix B is the same, just transposed:
B = b(index)';

How to count number of entries satisfying specific case?

A=[1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 1 2 3 4 5 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5;
0 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0;
0 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0];
What is code to count number "1" in the column which only has elements which have value greater than 1 and less than 4.
note: zeros is ignored.
Thus, My expected output is res = 1 which is in second column only.
Here is what I tried:
res = sum( sum(A(2 :end,all(A>1&A<4))==1, 2),1 );
but zeros are still being counted in my code.
If I understand it correctly, you could do it this way:
Start by finding all columns that violate the first rule that elements of A my not be greater than 4
[~, del, ~] = find(A>=4)
Remove those columns:
A(:, unique(del)) = []
Which gives:
A =
1 2 3 0 0 0 0 0
0 1 2 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 2 3
0 0 0 2 3 0 0 0
0 0 0 2 3 0 0 0
Now we find all remaining columns that have a 1:
[~, c1, ~] = find(A == 1);
And all columns that have at least one value greater than 1 following the second requirement:
[~, c2, ~] = find(A > 1)
These vectors c1 and c2 with the column numbers we then simply intersect and count:
numel(intersect(c1, c2))
Now there are plenty of Matlab wizards on this forum, and my instinct tells me there is a better answer, so perhaps you should wait a bit.