开发者

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 squeezi开发者_开发百科ng 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?


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]);


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);


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{:});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜