Shuffle row order within every N rows in a matrix

4 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

Categories

Find more on Resizing and Reshaping Matrices in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!