Clear Filters
Clear Filters

Shuffle row order within every N rows in a matrix

3 views (last 30 days)
I would like to shuffle my matrix's rows, but within each miniblock of 8 rows.
So for example, say I have the following 16x5 matrix:
[1 2 4 1 1
1 2 4 2 1
1 2 4 1 2
1 2 4 2 2
1 2 4 1 1
1 2 4 2 1
1 2 4 1 2
1 2 4 2 2
1 2 1 1 1
1 2 1 2 1
1 2 1 1 2
1 2 1 2 2
1 2 1 1 1
1 2 1 2 1
1 2 1 1 2
1 2 1 2 2];
How can I shuffle it so that the first 8 rows are all shuffled with eachother (maintaining column structure), and the second set of 8 rows are shuffled with eachother? Producing something like this:
[1 2 4 1 1
1 2 4 2 2
1 2 4 2 1
1 2 4 1 1
1 2 4 1 2
1 2 4 1 2
1 2 4 2 2
1 2 4 2 1
1 2 1 1 1
1 2 1 1 1
1 2 1 1 2
1 2 1 2 1
1 2 1 2 2
1 2 1 2 1
1 2 1 1 2
1 2 1 2 2];
In reality, my matrix is 384x5, so would be nice to be able to automate this somehow.
  3 Comments
Luca Ferro
Luca Ferro on 9 Feb 2023
why there is always a plot twist after people start answering lol :)

Sign in to comment.

Accepted Answer

Voss
Voss on 9 Feb 2023
Here's one way:
I'll use a different matrix that makes it easier to see that the process works:
data = repmat((1:8).'+(0:4),2,1);
disp(data);
1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9 6 7 8 9 10 7 8 9 10 11 8 9 10 11 12 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9 6 7 8 9 10 7 8 9 10 11 8 9 10 11 12
n_rows = 8;
N = size(data,1); % N must be a multiple of n_rows for this to work
n_shuffles = N/n_rows;
idx = zeros(n_rows,n_shuffles);
for ii = 1:n_shuffles
idx(:,ii) = randperm(n_rows);
end
new_data = data(idx(:),:);
disp(new_data);
3 4 5 6 7 5 6 7 8 9 2 3 4 5 6 6 7 8 9 10 4 5 6 7 8 8 9 10 11 12 1 2 3 4 5 7 8 9 10 11 3 4 5 6 7 5 6 7 8 9 8 9 10 11 12 7 8 9 10 11 1 2 3 4 5 4 5 6 7 8 2 3 4 5 6 6 7 8 9 10
  1 Comment
Rik
Rik on 10 Feb 2023
If your matrix is not a multiple of n_rows, you need edits like in my answer.

Sign in to comment.

More Answers (2)

Luca Ferro
Luca Ferro on 9 Feb 2023
Edited: Luca Ferro on 9 Feb 2023
i think this would do the trick:
[rows,~]=size(m);
if mod(rows,2)==0 %detects if even or odd number of rows
half=rows/2;
topHalf=m(1:half,:) %split matrix in half
bottomHalf=m(1+half :end,:)
else
half=(rows+1)/2; %the middle row will be left unshuffled
topHalf=m(1:half-1,:) %split matrix in half
bottomHalf=m(1+half :end,:)
end
topShuffle=randperm(half);
bottomShuffle=randperm(half);
m=[topHalf(topShuffle,:);bottomHalf(bottomShuffle,:)] %merges halves to recreate full

Rik
Rik on 9 Feb 2023
Just use a loop with randperm:
data=[
1 2 4 1 1
1 2 4 2 1
1 2 4 1 2
1 2 4 2 2
1 2 4 1 1
1 2 4 2 1
1 2 4 1 2
1 2 4 2 2
1 2 1 1 1
1 2 1 2 1
1 2 1 1 2
1 2 1 2 2
1 2 1 1 1
1 2 1 2 1
1 2 1 1 2
1 2 1 2 2];
k=4; % You want 8, but that is a big example
rng(0) % make the result the same each run for this example
sz = size(data,1);
for base_row=1:k:sz
base_row
block_indices = randperm( min(sz-base_row,k) );
ind1 = base_row + (1:numel(block_indices))
ind2 = base_row + block_indices
data(ind2,:) = data(ind1,:);
end
base_row = 1
ind1 = 1×4
2 3 4 5
ind2 = 1×4
4 2 3 5
base_row = 5
ind1 = 1×4
6 7 8 9
ind2 = 1×4
7 8 9 6
base_row = 9
ind1 = 1×4
10 11 12 13
ind2 = 1×4
12 10 11 13
base_row = 13
ind1 = 1×3
14 15 16
ind2 = 1×3
15 16 14

Community Treasure Hunt

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

Start Hunting!