如何在MATLAB中随机排列3D矩阵的列

6

我有一个3D矩阵(10000 x 60 x 20),我需要交换第二维和第三维,同时保持列不变。

对于2D矩阵,我使用RANDPERM:

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

我不能只是简单地两次使用RANDPERM——先是列索引,然后是页面索引。这样随机性不够。

一种解决方案是将矩阵从3D重塑为2D,将列和页面压缩为列,对它们进行排列,然后再次重塑。但我还想以这样的方式进行排列,即为每个页面单独排列列。类似于:

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

我能更有效地完成吗?有更好的方法吗?


1
@BlessedKey:实际上相反。每个 A(i,:,:) 都需要以相同的方式进行排列。这就是我所说的“保持列不变”的意思。A(i,randperm(size(A,2)),randperm(size(A,3)) 并不能给我足够的排列。它基本上是在列索引内部对页面索引进行排列。 - yuk
@yuk:另一个问题:您是否希望在页面之间随机排列列?还是在每个页面内随机排列列? - user616736
@yoda:如果我这样做A(i,randperm(size(A,2)),randperm(size(A,3))。所有的列和页都以相同的方式排列。为了更好地理解我的观点,请尝试x = reshape(1:24,4,6); x(randperm(4),randperm(6)) - yuk
@yoda:关于页面之间的列洗牌。是的,一开始我也考虑过这个问题。这就是我试图描述的一个解决方案,它将所有列视为独立的(正如@Amro的答案所述)。但后来我决定将列保留在它们所在的页面中,适用于我的特定情况。 - yuk
@yuk:我最初删除了它,因为Amro的答案的第二部分基本上已经涵盖了它。但现在我已经将其恢复,因为我认为对于初学者来说,跟随那个比担心线性索引更容易,尽管如果我要做到这一点,我会选择后者。 - user616736
显示剩余4条评论
3个回答

3

这里有一个解决方案,可以实现与您的for循环相同的结果(即每一页的不同列排列):

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

对于MATLAB中的许多问题,有许多不同的解决方法。这里提供另一种解决方案,通过仅使用线性索引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);

非常感谢。看起来很复杂,但我会尝试。 - yuk

3

解决方案#1:在所有页面上对列进行排列

将矩阵从3D重塑为2D,将列和页面压缩到列中,对它们进行排列,然后再次重塑

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

解决方案#2:在每个页面内独立排列列 (相当于您的for循环)

我还想以这样一种方式进行置换,即每个页面内独立排列列。

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

现在你可以从两个不同的解决方案中选择。 - Amro

1

这里有一个解决方案,与您的循环相同,但不使用 kron,就像gnovice的答案一样。虽然我更喜欢 kron,但如果您需要与不理解此处 kron 的人共享代码,则这是一个更安全的选择(我从经验中说)。但是,我必须指出,如果 pages 变得很大(在您的情况下,这是可以接受的),这将影响性能。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接