generate random numbers among each non zero column elements

23 visualizaciones (últimos 30 días)
Chaoyang Jiang
Chaoyang Jiang el 18 de Abr. de 2018
Editada: John D'Errico el 28 de Dic. de 2024 a las 14:44
Given a=[0 1 1; 1 1 1; 1 0 1], the row index of first elements of 1st colomn is [2 3], 2nd colomn is [1 2] and 3rd colomn is [1 2 3].
Then I want to generate random numbers among each row index, e.g.:
generate 1 random number from 1st column index [2 3],
generate 1 random number from 2nd column [1 2],
generate 2 random numbers from 3rd column [1 2 3].
The following code is what I've written to do this. It works but it seems not efficient especially when a is huge. Currently, I am using for-loop, may I know if anyone could have more efficient ways like the vectorized version to do this?
Thank you!
a=[0 1 0 0; 1 1 1 0; 1 0 0 1];
dind=1:3;
[a1,a2]=find(a==1);
e=[1 2 1 1];%define how many random numbers needed
d=cell(length(e),1);
for j=1:length(e)
c=a1(a2==j);%read the random number row index of j-th colomn
d{j}=dind(1,c(1:e(j)));%read the row index
a(c(1:e(j)),j)=0;%make the readed data into 0
end
  4 comentarios
KSSV
KSSV el 3 de Mayo de 2018
Read about logical indexing......
Chaoyang Jiang
Chaoyang Jiang el 3 de Mayo de 2018
Thank you for your hint...

Iniciar sesión para comentar.

Respuestas (2)

Madheswaran
Madheswaran el 28 de Dic. de 2024 a las 8:13
Hi Chaoyang,
Based on your reply to Jonas, I understand that you would like to get one random row index of any non-zero value for every columns in the matrix 'a'. You can achieve that using 'accumarray' and 'cellfun' and avoid the 'for loop'. Consider the follwing code:
[rows, cols] = find(a);
grouped_rows = accumarray(cols, rows, [], @(x) {x});
% Retrieve a random index from each non-empty group
selected_rows = cellfun(@(x) x(randi(length(x))), grouped_rows(~cellfun('isempty', grouped_rows)));
In the code above, the 'find' function is used to identify the row and column indices of non-zero values. These row indices are then grouped according to their respective column indices. Subsequently, a single index is randomly selected from each group of rows. This approach effectively eliminates the need for a 'for loop'.
For further details, please refer to the relevant MathWorks documentation:
  1. cellfun - https://mathworks.com/help/matlab/ref/cellfun.html
  2. accumarray - https://mathworks.com/help/matlab/ref/accumarray.html
Hope this is helpful to you!

John D'Errico
John D'Errico el 28 de Dic. de 2024 a las 14:40
Editada: John D'Errico el 28 de Dic. de 2024 a las 14:44
This is a 7 year old question, so there is probably no real utility in my posting an answer. But it is an interesting question that should have gotten an answer when posted. So, just to show there are always multiple ways to solve any problem, I'll offer a completely different solution to the entirely good solution offered by @Madheswaran. (I did actually upvote that answer.)
Given a binary matrix like that in a, we want to generate a random index for each column of a, where the index will pick out the row number of a random non-zero element. My alternative solution is a simple one.
a=[0 1 1; 1 1 1; 1 0 1];
Just generate a random matrix, of the same size as a. Then apply max, as follows:
[~,ind] = max(a.*rand(size(a)),[],1)
ind = 1×3
3 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
We only care about the second return argument from max. The trick of multiplying the random matrix element-wise with a turns all of the unwanted elements to zero, while not changing the corresponding unit elements of the random array. And zero will NEVER be the maximum element. Of the non-zero elements that remain, the location of the maximum will be uniformly distributed among them.
Note, that if any column of a is entirely zero, so no ones at all? This solution will return an index of 1 for that column. (The code proposed by @Madheswaran will fail for a different reason in that case.) You always need to consider these problematic cases, as they may be important, and cause a difficult to find bug in your code one day.
Is this a better solution to that proposed by @Madheswaran? No. Not necessarily. That depends on your definition of better, and the requirements of your problem. This is often the case for all "vectorized" solutions to any problem.
Since it works in only one line of code, you might argue it is a "good" solution indeed. In terms of a Cody metric to score the value of this solution, it would "win". And it has no need for tools like arrayfun and cellfun. HOWEVER, if a was a very large array that was mostly zeros, then generating a large array of random numbers, then tossing most of them away, unused, would be inefficient. And that could be a serious downside to my code. I think more important is to understand each solution, see what they do, why they work.

Community Treasure Hunt

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

Start Hunting!

Translated by