2014-08-29 60 views
5

在MATLAB中,我正在使用shake.m函数(http://www.mathworks.com/matlabcentral/fileexchange/10067-shake)随机混洗每列。例如:在MATLAB中随机移动矩阵有更好/更快的方式吗?

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),因此这需要很长的时间来运行。有谁知道实现这个更快的方法吗?我曾尝试单独晃动每个列向量,但这不是更快。谢谢!

+0

看看那个摇动函数,它看起来是完全向量化的,但它使用按列排序的矩阵。即在你的情况下,它会对> 10,000,000行的列进行排序,这并不令人惊讶。 – Nras 2014-08-29 07:30:49

回答

5

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

+1这非常聪明。 – Dan 2014-08-29 12:19:18

+0

@Dan这个想法(矢量化排序)[来自你](http://stackoverflow.com/a/25547312/2586922):-) – 2014-08-29 12:20:32

+0

+1的确非常有趣的方法!那么'排序'被证明是我解决方案的瓶颈。 – Divakar 2014-08-29 12:48:06

5

使用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

+0

'a'不是矢量... – Dan 2014-08-29 06:47:50

+0

@lakesh谢谢你 - 我不知道我是如何使用它来实际实现上述b的输出矩阵。我想垂直拖动列,即摇([1 4 7]);摇([2 5 8]);摇([3 6 9]); – user2861089 2014-08-29 06:47:58

+0

@Dan谢谢,已经纠正它.. – lakesh 2014-08-29 06:56:16

8

您可以使用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)不同的顺序,并且如果m远小于n(例如m=5,n=100000就像你的数据),那么这些顺序将自然重复。因此,不要让它自己发生,而是管理过程,并减少对randperm的调用,无论如何,这将产生相同的结果。

+0

谢谢@丹!我有10,000,000行和5列...我已经完成了1000行数据的快速概要汇总,前两个选项比已经快了!真棒。将尝试第三个建议。 – user2861089 2014-08-29 07:06:02

+1

@ user2861089注意第三点,根据'k'参数的不同,它可能不像第一个那样随机。你希望每个独特的'randperm'调用在平均*'n/factorial(m)'列上影响* – Dan 2014-08-29 07:09:30

4

这是一个无循环的方法,因为它一次处理所有指标,我相信这是随机的,因为只有在每列之间才能满足洗牌要求。在a本身获得

代码

%// 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)) 

最终输出。

+0

谢谢@Divakar - 刚刚测试过这个,但没有像上面的答案那么快。虽然谢谢! – user2861089 2014-08-29 07:42:22

+0

@Divakar,请添加一个解释 - 尤其是你最后一行 – Dan 2014-08-29 08:30:02

+0

@Dan最后一行看起来像是一个手动版本的'sub2ind'。手动执行通常比'sub2ind'快。 – 2014-08-29 11:09:05