2017-08-09 59 views
2

我有一个订单矩阵100*5。现在的目标是用特定范围内的随机整数填充矩阵的每一列。现在问题是每列随机数的范围发生变化。例如,对于第一列,范围是1到100,第二列是-10到1,以此类推到第五列。如何使用100 * 5矩阵的特定范围的随机数填充矩阵的列?

这是我已经试过:

b = [0,100;-10,1;0,1;-1,1;10,20] 
range = b(:,2) - b(:,1) 
offset = b(:,1) 
A = round(rand(100,5) * range - offset) 

这是从this问题。然而,这会产生一个错误,

错误使用*内部矩阵尺寸必须一致。

什么可能导致这种情况,以及如何解决它?

+0

避免更改var名称后,同样的错误Persis – EBH

+0

@EBH即使 – OBX

+0

这不是错误的原因,只是一个好习惯。 – EBH

回答

4

bsxfun这个东西!

A = round(bsxfun(@minus,bsxfun(@times,rand(100,5) ,range'), offset')) 
+1

这是一个史诗般的答案,谢谢! – OBX

+3

@OBX好像你从一个真正的巫师得到了答案! – EBH

+0

顺便说一句,我认为'randi'更快,但我不确定它的实现更简单。 – EBH

2

你可以用randi做到这一点,在b行传递给它的第一个参数:

b = [0,100;-10,1;0,1;-1,1;10,20]; 
A = zeros(100,5); 
[email protected](ii)randi(b(ii,:),100,1); 
for ii = 1:size(A,2) 
    A(:,ii) = f(ii); 
end 

我怀疑有这样做,而无需通过行/列循环,可能与bsxfun的一种方式。

+0

谢谢,这可以做到不使用循环? – OBX

+0

@OBX请参阅编辑。也许,但我不够的一个MATLAB向导 – Steve

+1

啊! Matlab的wizars是必要的! :P很高兴在这里找到你! –

2

您可以使用arrayfun,尽管我没有看到任何伤害,使用循环和编写更可读的代码在史蒂夫的答案。

A = cell2mat(arrayfun(@(imin, imax) randi([imin, imax], 100, 1), b(:,1), b(:,2), 'uni', 0)') 
+0

如果我没有错,'arrayfun' **是一个循环(内部)。 –

+0

它比简单的'for'慢。 – EBH

3

作为替代解决方案,你可以使用repmat完成你已经有:

b = [0, 100; -10, 1; 0, 1; -1, 1; 10, 20].'; 
rng = b(2, :) - b(1, :); 
ofst = b(1, :); 
A = round(rand(100,5) .* repmat(rng, 100, 1) + repmat(ofst, 100, 1)); 

你不必定义rngofst,这可以简单地写为:

A = round(rand(10,5) .* repmat(diff(b), 10, 1) + repmat(b(1,:), 10, 1)); 

出于好奇,我写这个问答uick基准*与Ander的bsxfun方法进行比较。看起来bsxfun有一些初始开销,这意味着对于5列(自己测试其他情况)和少于几千行,repmat更快。在此之上,通过repmat创建更多大型阵列可能会导致速度放慢,而我们看到bsxfun速度更快。

small vals large vals

对于未来的读者,如果这并不适用于你:broadcasting introduced from R2016b你会发现你可以使用bsxfunrepmat完全闪避。

*基准代码。在Windows 64位R2015b上测试,您的里程可能会有所不同。

function benchie() 
    b = [0, 100; -10, 1; 0, 1; -1, 1; 10, 20].'; 
    Tb = []; 
    Tr = []; 
    K = 20; 
    for k = 1:K 
     n = 2^k; 
     fb = @()bsxfunMethod(b,n); 
     fr = @()repmatMethod(b,n); 
     Tb(end+1) = timeit(fb); 
     Tr(end+1) = timeit(fr); 
    end 
    figure; plot(2.^(1:K), Tb, 2.^(1:K), Tr); legend('bsxfun', 'repmat'); 
end 
function bsxfunMethod(b, n) 
    round(bsxfun(@minus,bsxfun(@times, rand(n,5), diff(b)), b(1,:))); 
end 
function repmatMethod(b, n) 
    round(rand(n,5) .* repmat(diff(b), n, 1) + repmat(b(1,:), n, 1)); 
end 
使用`range`作为变量名,因为它是一个[函数名](http://www.mathworks.com/help/stats/range.html?s_tid=doc_ta)
+0

'repmat'比'bsxfun'快[结果有点令人惊讶](https://stackoverflow.com/questions/29719674/comparing-bsxfun-and-repmat)。 – EBH

+0

感谢您的链接,您是否可以在自己的机器上复制我的结果?我觉得上面的基准是合理的,但是当然这个问题的用例细微差别可能会影响事物!正如我推测,可能会有一些初始的'bsxfun'开销,因为它对于大型数组来说要快得多 – Wolfie

+0

当我运行1-10000行的范围时,我得到一个[噪声模式](https://i.stack。 imgur.com/q2ym9.png),对'repmat'具有一般优势。当我运行2-2^20的范围时,我会得到和你一样的结果。 – EBH