Arrays 在MATLAB中有更好/更快的随机洗牌矩阵的方法吗?

Arrays 在MATLAB中有更好/更快的随机洗牌矩阵的方法吗?,arrays,matlab,matrix,Arrays,Matlab,Matrix,在MATLAB中,我使用shake.m函数()随机洗牌每一列。例如: a = [1 2 3; 4 5 6; 7 8 9] a = 1 2 3 4 5 6 7 8 9 b = shake(a) b = 7 8 6 1 5 9 4 2 3 这个函数正是我想要的,但是我的列非常长(>10000000),所以运行这个函数需要很长时间。有人知道

在MATLAB中,我使用shake.m函数()随机洗牌每一列。例如:

a = [1 2 3; 4 5 6; 7 8 9]
a =

     1     2     3
     4     5     6
     7     8     9

b = shake(a)
b =

     7     8     6
     1     5     9
     4     2     3

这个函数正是我想要的,但是我的列非常长(>10000000),所以运行这个函数需要很长时间。有人知道一种更快的方法来实现这一点吗?我尝试过分别摇晃每个列向量,但这并不快。谢谢

使用randperm获得无序索引

idx = randperm(size(a,1));
使用索引对向量进行洗牌:

m = size(a,1);
for i=1:m
 b(:,i) = a(randperm(m,:);
end

看看这个答案:

你可以像这样使用
randperm
,但我不知道它是否会比
shake
更快:

[m,n]=size(a)
for c = 1:n
    a(randperm(m),c) = a(:,c);
end
或者您可以尝试切换
randperm
,看看哪个更快(应该会产生相同的结果):

否则,您有多少行?如果您的行远少于列,那么我们可能会假设每个排列都会重复,那么下面的情况如何:

[m,n]=size(a)
cols = randperm(n);
k = 5;  %//This is a parameter you'll need to tweak...
set_size = floor(n/k);
for set = 1:set_size:n
    set_cols = cols(set:(set+set_size-1))
    a(:,set_cols) = a(randperm(m), set_cols);
end

这将大大减少调用
randperm
的次数。但是,将其拆分为大小相同的
k
集合可能不是最佳选择,您可能还需要添加一些随机性。不过,这里的基本思想是,只有
factorial(m)
不同的排序,如果
m
n
小得多(例如
m=5
n=100000
,就像您的数据一样),那么这些排序将自然重复。因此,与其让它自己发生,不如管理这个过程,减少对
randperm
的调用,这样无论如何都会产生相同的结果。

这里有一个无循环的方法,因为它一次处理所有索引,我相信这是随机的,因为考虑到只在每个列之间洗牌的要求

代码

%// Get sizes
[m,n] = size(a);

%// Create an array of randomly placed sequential indices from 1 to numel(a)
rand_idx = randperm(m*n);

%// segregate those indices into rows and cols for the size of input data, a
col = ceil(rand_idx/m);
row = rem(rand_idx,m);
row(row==0)=m;

%// Sort both these row and col indices based on col, such that we have col
%// as 1,1,1,1 ...2,2,2,....3,3,3,3 and so on, which would represent per col
%// indices for the input data. Use these indices to linearly index into a
[scol,ind1] = sort(col);
a(1:m*n) = a((scol-1)*m + row(ind1))

最终输出在
a
本身中获得。

这里有一个简单的矢量化方法。请注意,它会创建一个与
a
大小相同的辅助矩阵(
ind
),因此根据您的内存,它可能可用或不可用

[~, ind] = sort(rand(size(a))); %// create a random sorting for each column
b = a(bsxfun(@plus, ind, 0:size(a,1):numel(a)-1)); %// convert to linear index

@lakesh对此表示感谢-我不确定如何使用它来实际实现上面为b提供的输出矩阵。我想垂直洗牌列,即抖动([1 4 7]);摇晃([2 5 8]);摇晃([3 6 9])@如果速度是一个问题,那么在循环之前,尽可能地计算所有东西是有意义的。所以
大小(a,1)
不需要计算10000000次,因为它总是相同的。谢谢@Dan!我有10000000行和5列。。。我已经对1000行数据做了一个快速概要文件总结,您的前两个选项已经比shake快了!令人惊叹的。将尝试第三个建议。@user2861089注意第三个建议,根据
k
参数的不同,它可能不像前两个建议那样随机。您希望对
randperm
的每个唯一调用平均影响
n/factorial(m)
columnsLooking在该shake函数中,它看起来是完全矢量化的,但它在矩阵列上使用排序。也就是说,在你的例子中,它对超过10000000行的列进行排序,这并不奇怪,速度很慢。谢谢@Divakar-刚刚测试了这一点,但没有上面的答案那么快。谢谢你@Divakar,请添加一个解释-尤其是你最后的解释line@Dan最后一行看起来像是手动版本的
sub2ind
。手动操作通常比添加注释的
sub2ind
更快。正如Luis所指出的,最后一行基本上是一种“原始”的方法,用于
sub2ind
,输入来自
scol
row(ind1)
,它们是已排序的列和行索引。@Dan思想(矢量化排序):-)+1确实是一种非常有趣的方法!嗯,
排序
被证明是我解决方案中的瓶颈。我也是+1。我以前从未见过像这样洗牌。@rayryeng谢谢!实际上,
randperm
就是这么做的internally@LuisMendo这很好-比Ben的建议快1秒,比Divakar的建议快10秒(使用
a=rand(10000000,5);
)!
[~, ind] = sort(rand(size(a))); %// create a random sorting for each column
b = a(bsxfun(@plus, ind, 0:size(a,1):numel(a)-1)); %// convert to linear index