Say I have a matrix, I would like to shuffle the elements within the rows randomly. For example,
A = randi(1000, 3,4)
A =
815 279 958 793
906 547 486 960
127 958 801 656
I need to get the shuffled matrix like this
B =
279 793 958 815
960 547 486 906
801 127 958 656
The most straightforward way I can think of achieving this is to use randperm to shuffle the indices of each row, and then loop over the number of rows to create the shuffled matrix. But I would like to get it all done in one go, preferably more elegantly than using a loop, because I need to do this for large matrices many times. So, alternatively, I tried this:
[nr,nc] = size(A);
P=perms(1:nc);
col_indx_mtrx = P(randi(size(P,1),nr,1),:);
ri = repmat((1:nr)',1,nc);
which gives me
ri =
1 1 1 1
2 2 2 2
3 3 3 3
col_indx_mtrx =
2 1 4 3
3 4 1 2
1 4 2 3
Now, after this, I thought if I simply do
B = A(ri,col_indx_mtrx)
I am done. But, I don't get the desired result, because when I give the row and column indices as matrices, MATLAB tries to create a matrix with all combinations of the row and column indices?
Essentially, what I need is to create the shuffled matrix B such that
B(1,1) = A(ri(1,1), col_indx_mtrx(1,1))
and so on. Is there an elegant way to achieve this last step? I tried to use arrayfun, but I could not get it done.
Or, better, is there a more elegant way of achieving the overall objective?
Any help would be greatly appreciated.

 Akzeptierte Antwort

the cyclist
the cyclist am 24 Okt. 2015

3 Stimmen

Here's one way:
% Original matrix
A = randi(1000, 3,4);
[M,N] = size(A);
% Preserve the row indices
rowIndex = repmat((1:M)',[1 N]);
% Get randomized column indices by sorting a second random array
[~,randomizedColIndex] = sort(rand(M,N),2);
% Need to use linear indexing to create B
newLinearIndex = sub2ind([M,N],rowIndex,randomizedColIndex);
B = A(newLinearIndex);

3 Kommentare

Par
Par am 29 Okt. 2015
Thanks for the answer! The main difference in my method and yours, I notice, is the way of generating the randomizedColIndex. I like yours better, and so have used it. If we use perms, instead, as I was doing, MATLAB is likely to go out of memory very quickly.
Thanks also to Thorsten below.
Sahil Bansal
Sahil Bansal am 30 Apr. 2017
Bearbeitet: Sahil Bansal am 30 Apr. 2017
And how can I shuffle the elements in the column randomly?
Jan
Jan am 30 Apr. 2017
Bearbeitet: Jan am 30 Apr. 2017
Sorting random indices is less efficient and has a tiny bias compared to the stable Fisher Yates shuffle: There is (and must be) the chance, that rand(1, 2) replies two equal numbers. Matlab's sort is stable, such that the first occurrence is preferred.
In older Matlab versions randperm used the sorting of random vectors also, but now the relation between data size and runtime looks like the faster Fisher Yates shuffle is used also, when it is called with 2 inputs:
tic;
v = randperm(1e6);
toc;
tic;
v = randperm(1e6, 1e6);
toc;
Elapsed time is 0.204787 seconds.
Elapsed time is 0.086091 seconds.
I've delivered a suggestion for improvements.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (3)

Matt J
Matt J am 24 Okt. 2015
Bearbeitet: Matt J am 26 Okt. 2015

2 Stimmen

[m,n]=size(A);
T=perms(1:n); %tabulate once only
J=T(randi(m,m,1),:);
B=A( bsxfun(@plus,(1:m).', (J-1)*m) );
Thorsten
Thorsten am 26 Okt. 2015
Bearbeitet: Thorsten am 26 Okt. 2015
To achieve the last step in your code, use sub2ind:
B = A(sub2ind([nr nc], ri, col_indx_mtrx));

Kategorien

Mehr zu Sparse Matrices finden Sie in Hilfe-Center und File Exchange

Gefragt:

Par
am 24 Okt. 2015

Bearbeitet:

Jan
am 30 Apr. 2017

Community Treasure Hunt

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

Start Hunting!

Translated by