yuk
yuk

Reputation: 19870

How to randomly permute columns in 3D matrix in MATLAB

I have 3D matrix (10000 x 60 x 20) and I need to permute 2nd and 3rd dimensions keeping the columns intact.

For 2D matrix I use RANDPERM:

pidx = randperm(size(A,2));
Aperm = A(:,pidx);

I cannot just apply RANDPERM twice - column index first, then page index. Not enough randomization.

One solution is to reshape the matrix from 3D to 2D squeezing columns and pages to columns, permute them and then reshape back. But I'd also like to do permutation in such a way that columns permuted independently for each page. Something like:

Aperm = zeros(size(A));
for p=1:size(A,3)
    pidx = randperm(size(A,2));
    Aperm(:,:,p) = A(:,pidx,p);
end

Can I do it more efficiently? Any better ways?

Upvotes: 6

Views: 3959

Answers (3)

gnovice
gnovice

Reputation: 125854

Here's one solution that will achieve the same result as your for loop (i.e. a different permutation of columns for each page):

%# Solution 1:
[r,c,p] = size(A);
Aperm = reshape(A,r,c*p);
index = arrayfun(@randperm,c.*ones(1,p),'UniformOutput',false);
index = [index{:}]+kron(0:c:c*(p-1),ones(1,c));
Aperm = reshape(Aperm(:,index),r,c,p);

And, as with many problems in MATLAB, there are a number of different ways to solve this. Here's another solution that avoids reshaping of the matrix by using only linear indexing into A:

%# Solution 2:
[r,c,p] = size(A);
Aperm = zeros([r c p]);
index1 = repmat(1:r,1,c*p);
[~,index2] = sort(rand(c,p));          %# A variation on part of Amro's answer
index2 = kron(index2(:),ones(r,1)).';  %'
index3 = kron(1:p,ones(1,r*c));
index = sub2ind([r c p],index1,index2,index3);
Aperm(:) = A(index);

Upvotes: 3

Amro
Amro

Reputation: 124563

Solution#1: Columns are permuted across all pages

reshape the matrix from 3D to 2D squeezing columns and pages to columns, permute them and then reshape back

A = randi(10, [3 4 2]);                 %# some random 3D matrix

[r c p] = size(A);
Aperm = reshape(A, [r c*p]);
Aperm = reshape(Aperm(:,randperm(c*p)), [r c p]);

Solution#2: Columns are permuted within each pages independently (equivalent to your for-loop)

I'd also like to do permutation in such a way that columns permuted independently for each page

A = randi(10, [3 4 2]);                 %# some random 3D matrix

[r c p] = size(A);
Aperm = reshape(A, [r c*p]);

[~,idx] = sort(rand(p,c),2);            %# this is what RANDPERM does
idx = reshape(bsxfun(@plus, idx',0:c:c*(p-1)),1,[]);    %'#

Aperm = reshape(Aperm(:,idx), [r c p]);

Upvotes: 3

abcd
abcd

Reputation: 42225

Here's a solution that's the same as your loop, but without using kron as in gnovice's answer. Although I prefer kron, this is a safer alternative if you happen to be sharing code with people who won't understand what kron does here (I speak from experience). I must however note that this will affect performance if pages becomes large (in your case, it is ok).

[rows,cols,pages]=size(A);
randCols=arrayfun(@(x)randperm(cols),1:pages,'UniformOutput',false);
Aperm=arrayfun(@(x)A(:,randCols{x},x),1:pages,'UniformOutput',false);
Aperm=cat(3,Aperm{:});

Upvotes: 1

Related Questions