Select random data from a matrix and replace it

Hello,
I have the following problem: I have a matrix e.g
1 0 1 0 1
1 1 1 0 0
1 1 1 1 1
1 1 0 0 1
and I try to do this: When the sum of each column exceeds the threshold=4 some random "1" of the column that goes beyond the threshold become zero. How do I implement this in matlabThis can be done without using loops?I would be very grateful if someone helpend me

 Accepted Answer

Andrei Bobrov
Andrei Bobrov on 14 May 2019
Edited: Andrei Bobrov on 15 May 2019
A = [1 0 1 0 1
1 1 1 0 0
0 0 0 0 0
1 1 1 1 1
1 1 0 0 1
0 0 0 0 0];
p = 4;
[ii,jj] = find(A);
jjj = accumarray(ii,jj,[size(A,1),1],@(x){x(randperm(numel(x),min(numel(x),p)))});
k = cellfun(@numel,jjj);
out = accumarray([repelem((1:numel(k))',k),cell2mat(jjj)],1,size(A));

5 Comments

Stelios's "Answer" moved here:
I tried what you have told me. I tried in a matrix 840X1145 (that is matrix A has dimensions of 840X1145) and the resulting out matrix has dimensions of 840X1140. Why is that? Also, I will use the matrix out in other calculations, but Matlab errors out due to dimension mismatch. How does this solution work?
Please attach your matrix "A" in a .mat file with the paper clip icon.
The matrix A that I mention is a matrix 840X1145 and contains "1" and "0" and I tested the above solution the new matrix resulting i.e the matrix out has dimensions 840X1140. How to solve this problem because the matrix out it should also have dimensions of 840X1145 so I can make some other calculations.
It works!!!Thank you very much!!!!!!

Sign in to comment.

More Answers (2)

Here is another, indexing, approach:
A = randi(2, 6, 8)-1 % random 0/1 array
M = 3 % max number of 1's per column
szA = size(A) ;
B = zeros(szA) ;
tf = A == 0 ;
[~, P] = sort(rand(szA)) ; % randperm for matrix along columns
P(tf) = 0 ;
[~, r] = maxk(P, M) ; % rows with M highest values in P (including 0's) per column
i = r + szA(1)*(0:szA(2)-1) ; % convert to linear indices
B(i) = 1 ; % B contains M 1's per column
B(tf) = 0 % reset those that were 0 in A -> only maximally M 1's per column remain

2 Comments

Works what I suggest and thank you very much!!!
I just have the following question: Once matrix B is created with
0 's and 1 's how it stays stable without changing put 0 's and 1's every time i run the code?
I don't get it. Why not simply run the code only once for a given matrix A?

Sign in to comment.

Jan
Jan on 16 May 2019
Edited: Jan on 16 May 2019
A logical mask is much simpler than handling the indices:
A = randi([0,1], 8, 8); % Test data
p = 4;
mask = (cumsum(A, 1) > p) & A;
A(mask) = randi([0,1], nnz(mask), 1);
This replaces 1s in each column by a 0 with a probability of 50%, but leaves the first p ones untouched.
But if you want to change any 1s without keeping the first p 1s of each column:
mask = (sum(A, 1) > p) & A; % cumsum -> sum, auto-expand: >= R2016b
A(mask) = randi([0,1], nnz(mask), 1);
If you want to replace the 1s in the columns with more than p 1s with another probability:
A(mask) = rand(nnz(mask), 1) > 0.85;

3 Comments

I assumed that the OP wanted to leave a maximum number (M) of ones in each column. If there are more than M ones in a column, a random selection of those should be set to 0, so M ones remain.
Jan
Jan on 16 May 2019
Edited: Jan on 16 May 2019
@Jos: A maximum number of ones? Do you mean a minimum number of ones? I admit, I'm more and more confused.
From the OP: "When the sum of each column exceeds the threshold=4 some random "1" of the column that goes beyond the threshold become zero."
If I now read it again, just a single one in such a column should be set to 0 then? ...

Sign in to comment.

Categories

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!