Arrays 在MATLAB中有更好/更快的随机洗牌矩阵的方法吗?
在MATLAB中,我使用shake.m函数()随机洗牌每一列。例如: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),所以运行这个函数需要很长时间。有人知道
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