2017-08-09 58 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