【问题标题】:Is there a better/faster way of randomly shuffling a matrix in MATLAB?在 MATLAB 中是否有更好/更快的随机洗牌矩阵的方法?
【发布时间】:2014-10-23 03:27:11
【问题描述】:

在 MATLAB 中,我使用 Shake.m 函数 (http://www.mathworks.com/matlabcentral/fileexchange/10067-shake) 随机打乱每一列。例如:

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

这个函数完全符合我的要求,但是我的列非常长(>10,000,000),因此运行需要很长时间。有谁知道实现这一目标的更快方法?我试过分别摇动每个列向量,但这并不快。谢谢!

【问题讨论】:

  • 看看那个shake-function,它似乎是完全矢量化的,但它在矩阵列上使用排序。 IE。在您的情况下,它对超过 10,000,000 行的列进行排序,这并不奇怪。

标签: arrays matlab matrix


【解决方案1】:

randperm可以这样用,不知道会不会比shake快:

[m,n]=size(a)
for c = 1:n
    a(randperm(m),c) = a(:,c);
end

或者您可以尝试切换randperm 看看哪个更快(应该产生相同的结果):

[m,n]=size(a)
for c = 1:n
    a(:,c) = a(randperm(m),c);
end

否则你有多少行?如果行数远少于列数,我们可以假设每个排列都会重复,那么这样的情况如何:

[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) 不同的排序,如果mn 小得多(例如m=5n=100000 喜欢你的数据),那么这些排序将自然地重复.因此,与其让这种情况自行发生,不如管理流程并减少对randperm 的调用,这无论如何都会产生相同的结果。

【讨论】:

  • 谢谢@Dan!我有 10,000,000 行和 5 列...我已经对 1000 行数据进行了快速的个人资料摘要,您的前两个选项已经比抖动更快了!惊人的。将尝试第三个建议。
  • @user2861089 注意第三个,它可能不像前两个那样随机,具体取决于k 参数。您希望每个对 randperm 的唯一调用都会影响 平均 n/factorial(m)
【解决方案2】:

这是一个简单的矢量化方法。请注意,它会创建一个与 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

【讨论】:

  • @Dan 想法(矢量化排序)came from you :-)
  • +1 确实非常有趣的方法!好吧,sort 被证明是我解决方案的瓶颈。
  • 我也是+1。我以前从未见过这样的洗牌。
  • @rayryeng 谢谢!实际上这就是 randperm 在内部所做的
  • @LuisMendo 这很棒 - 比 Ben 的建议快 1 秒,比 Divakar 的建议快 10 秒(使用 a = rand(10000000,5); 时)!
【解决方案3】:

使用 randperm 获取洗牌索引

idx = randperm(size(a,1));

使用索引来打乱向量:

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

看看这个答案:Matlab: How to random shuffle columns of matrix

【讨论】:

  • @lakesh 对此表示感谢 - 我不确定我如何使用它来实际实现上面的 b 输出矩阵。我想垂直洗牌,即摇([1 4 7]);摇([2 5 8]);摇([3 6 9]);
  • @lakesh 如果速度是一个问题,那么在循环之前计算所有可能的东西是有意义的。所以size(a,1) 不需要计算 10000000 次,它总是一样的。
【解决方案4】:

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

代码

%// 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本身中获得。

【讨论】:

  • 谢谢@Divakar - 刚刚测试了这个,但没有上面的答案那么快。不过谢谢!
  • @Divakar,请添加解释——尤其是最后一行
  • @Dan 最后一行看起来像 sub2ind 的手动版本。手动操作通常比sub2ind 快​​。
  • @Dan 添加了 cmets。正如 Luis 所指出的,最后一行基本上是 sub2ind 的“原始”方法,输入来自 scolrow(ind1),它们是已排序的列和行索引。
猜你喜欢
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-12
  • 1970-01-01
  • 2021-02-02
  • 2015-01-14
相关资源
最近更新 更多