How can I generate a Matrix with Boolean elements, but the sum of each row is equal to a certain constant number.
Is each row the same one number?
k = 5;
m = 10;
n = 10;
[~, I] = sort(rand(m,n), 2)
M = I <= k
If you don't want the same number of 1s in each row, but rather have a vector that specifies per row how many 1s you want then you need to use bsxfun as well:
K = (1:10)'; %//'
m = 10;
n = 10;
[~, I] = sort(rand(m,n), 2)
M = bsxfun(#ge, K,I)
Lets say you want to have 20 columns (n=20) and your vector a contains the number of ones you want in each row:
n=20;
a= [5 6 1 9 4];
X= zeros(numel(a),n);
for k=1:numel(a)
rand_order=randperm(n);
row_entries=[ones(1,a(k)),zeros(1,n-a(k))];
row_entries=row_entries(rand_order);
X(k,:)=row_entries;
end
X=boolean(X);
What I do is generate me a random ordered index array rand_order then getting an array which contains the wanted number of ones filled with zero. Reorder those elements according to rand_order saving it and converting it to logical. And because of the use of a for loop rand_order is all the time computed again, so giving you different locations for your output:
1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0
0 0 0 1 0 0 0 1 1 0 1 0 0 0 0 0 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
1 0 0 1 0 1 1 0 1 0 0 1 1 0 0 0 1 1 0 0
1 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
Related
I'm trying to generate a randomly scattered but limited number of 1's in a matrix of zeros efficiently.
Say I have a 10x10 matrix of zeros (zeros(10)) and I want to randomly place ten 1's so it looks like:
0 0 0 0 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
0 0 0 0 0 0 0 0 1 0
1 0 0 0 0 1 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 1 0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
How can I do this WITHOUT a for-loop and without manually plugging in each position (this example is a much smaller version of my real problem)?
My code so far:
% Generate zeros
M = zeros(10)
% Generate random indices
Rands = [randsample(10, 10) randsample(10, 10)]
Where the first column is intended to be the row indices and the second column the column indices.
Now I obviously can't just drop these indices into the row and column indices of M like this:
M(Rands(:,1), Rands(:,2)) = 1
How can I vecorise the changes to these random indices?
You can use randperm to randomly generate the linear indices to be filled with 1:
sz = [10 10]; % desired size
n = 10; % desired number of ones
M = zeros(sz);
M(randperm(prod(sz), n)) = 1;
Alternatively, you can use randperm and reshape in one line:
M = reshape(randperm(prod(sz))<=n, sz);
You can use sub2ind to convert subscripts to linear index:
M(sub2ind(size(M),Rands(:,1),Rands(:,2)))=1
Is there a quick way to change the diagonals beside the center diagonal (referring to the 1s below):
m =
2 1 0 0 0 0 0 0 0
1 2 1 0 0 0 0 0 0
0 1 2 1 0 0 0 0 0
0 0 1 2 1 0 0 0 0
0 0 0 1 2 1 0 0 0
0 0 0 0 1 2 1 0 0
0 0 0 0 0 1 2 1 0
0 0 0 0 0 0 1 2 1
0 0 0 0 0 0 0 1 2
A quick way to change the center diagonal is m(logical(eye(size(m)))) = 2. How about assigning the diagonals beside it to values of 1?
The diag function takes a second parameter, k, which specifies which diagonal to target:
diag([-1,-1,-1,-1],-1) % or diag(-1*ones(4,1),1)
ans =
0 0 0 0 0
-1 0 0 0 0
0 -1 0 0 0
0 0 -1 0 0
0 0 0 -1 0
diag([1,1,1,1],1)
ans =
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 0
diag([2,2,2],2)
ans =
0 0 2 0 0
0 0 0 2 0
0 0 0 0 2
0 0 0 0 0
0 0 0 0 0
If you already have an existing matrix and you want to change one of the diagonals you could do this:
M = magic(5) % example matrix
v = [1,2,3,4] % example vector that must replace the first diagonal of M, i.e. the diagonal one element above the main diagonal
M - diag(diag(M,1),1) + diag(v,1)
The idea is to first use diag to extract the numbers of the diagonal you want to change, diag(M,1). Then to use diag again to change the vector that the first call to diag created into a matrix, diag(diag(M,1),1). You'll notice that this creates a matrix with the same dimensions as M, the same numbers as M on the 1st diagonal and 0s everywhere else. Thus M - diag(diag(M,1),1) just sets that first diagonal to 0. Now diag(v,1) creates a matrix with the same dimensions as M that is 0 everywhere but with the numbers of v on the first diagonal and so adding diag(v,1) only affects that first diagonal which is all 0s thanks to -diag(diag(M,1),1)
An alternative if you are just applying a constant to a diagonal (for example setting all the values on the first diagonal below the main diagonal to 6):
n = 5;
k = -1;
a = 6;
M = magic(n);
ind = diag(true(n-abs(k),1),k);
M(ind) = a;
I need to replace the repeated elements in column of a matrix as 0's and delete the rows which has all 0's. If my matrix is like this means.
Input =
1 0 0 1
0 1 0 1
0 0 1 1
1 1 1 1
My expected output should be like this
Output =
1 0 0 1
0 1 0 0
0 0 1 0
0 0 0 0 ---> this row should be get deleted in this case
This doesn't work for my problem
c = [ 1 1 0 1 0 1 1 1 0 1 1 0];
[c, ic] = unique(a, 'first');
c(~ismember(1:length(a),ic)) = 0;
You can use logical indexing and cumsum:
A = [1 0 0 1;
0 1 0 1;
0 0 1 1;
1 1 1 1];
ind = cumsum(A); %cumulative sum (by column)
A(ind>1) = 0;
A(sum(A')==0,:)=[]
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
So what I am trying to do is simply select random '1' element from logical matrix in matlab.
Suppose I have a matrix like this:
A= 0 1 1 1 0
0 1 0 1 1
1 0 0 0 0
0 0 1 0 0
0 0 0 0 0
and I have a number n which is a number that represent how many '1' elements will be selected in the procedure
For example if n=3 then the output can be looks like this:
A'= 0 1 0 0 0
0 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
*note that the maximum value possible for n is the number of '1' elements in matrix being processed
You should find the indexes of the 1s, choose n unique random integers, and handle those indexes:
n = 3;
A= [0 1 1 1 0;
0 1 0 1 1;
1 0 0 0 0;
0 0 1 0 0;
0 0 0 0 0];
% // idx of the ones in the matrix, also has information on size
idx = find(A == 1);
% // n unique rand numbers from 1 till nr_of_ones
randidx = randperm(numel(idx), n);
% // new matrix
B = zeros(size(A));
% // select the random indexes
B(idx(randidx)) = 1