2017-08-09 20 views
2

Ich habe eine Matrix der Bestellung 100*5. Jetzt ist das Ziel, jede Spalte der Matrix mit einer zufälligen ganzen Zahl innerhalb eines bestimmten Bereichs zu füllen. Jetzt ist das Problem für jede Spalte der Bereich der Zufallszahl ändert sich. Für die erste Spalte ist der Bereich beispielsweise 1 bis 100, für die Sekunde deren -10 bis 1 und so weiter bis zur fünften Spalte.Wie man Spalten einer Matrix mit Zufallszahlen des spezifischen Bereichs einer 100 * 5 Matrix füllt?

Dies ist, was ich versucht habe:

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) 

, die aus this Frage. Dies erzeugt jedoch einen Fehler,

Fehler bei der Verwendung * Innere Matrix Abmessungen müssen übereinstimmen.

Was verursacht dies möglicherweise und wie löst man es?

+0

Vermeiden 'range' als Variablennamen verwenden, da es sich um eine [Funktionsname] ist (http://www.mathworks.com/help/stats/range.html?s_tid=doc_ta) – EBH

+0

@EBH Selbst nach dem Ändern der Var-Name, der gleiche Fehler persis – OBX

+0

Dies ist nicht die Ursache für den Fehler, nur eine gute Gewohnheit. – EBH

Antwort

4

können bsxfun dieses Ding!

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

Das ist eine epische Antwort, danke! – OBX

+3

@OBX Scheint so, als hättest du eine Antwort von einem echten Zauberer bekommen! – EBH

+0

BTW, Ich denke, Randi ist schneller, aber ich bin mir nicht sicher, es ist einfacher, es damit zu implementieren. – EBH

2

Sie können dies tun, mit randi, in Reihen von b zu seinem ersten Argumente übergeben:

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 

Ich vermute, es gibt einen Weg, dies zu tun, ohne Zeilen/Spalten Schleifen, wahrscheinlich mit bsxfun.

+0

Danke, kann dies ohne die Verwendung von for-Schleife getan werden? – OBX

+0

@OBX Siehe Bearbeiten. Wahrscheinlich, aber ich bin nicht genug von einem MATLAB-Assistenten – Steve

+1

Ah! Matlab-Wizare werden benötigt! : P Freu dich, dich hier zu finden! –

2

können Sie arrayfun verwenden, obwohl ich sehe keinen Schaden in Loops und lesbaren Code wie in Steves Antwort zu schreiben.

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

Wenn ich nicht falsch liege, ist 'arrayfun' ** ** eine Schleife (innen). –

+0

Und es ist langsamer als ein einfaches 'for'. – EBH

3

Als alternative Lösung könnten Sie repmat zu vervollständigen verwenden, was Sie bereits:

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)); 

Sie müssen rng oder ofst nicht definieren, und dies kann einfach geschrieben werden als:

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

aus Neugier habe ich diesen q uick Benchmark * zu Anders bsxfun Methode zu vergleichen. Es scheint, dass bsxfun hat einige anfängliche Gemeinkosten, die für 5 Spalten bedeutet (andere Fälle testen Sie selbst) und weniger als ein paar tausend Zeilen, repmat ist schneller. Darüber hinaus verursacht die Erstellung von zusätzlichen großen Arrays durch repmat wahrscheinlich eine Verlangsamung, und wir sehen bsxfun ist viel schneller.

small vals large vals

Für zukünftige Leser, wenn dies für Sie nicht gilt: mit broadcasting introduced from R2016b Sie finden können Sie ausweichen können ganz bsxfun und repmat verwenden.

* Benchmarking-Code. Getestet auf Windows 64-bit R2015b, Ihre Laufleistung kann variieren usw.

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 
+0

Das Ergebnis, dass 'repmat' schneller ist als' bsxfun' ist [etwas überraschend] (https://stackoverflow.com/questions/29719674/comparing-bsxfun-and-repmat). – EBH

+0

Danke für den Link, können Sie meine Ergebnisse auf Ihrer eigenen Maschine replizieren? Ich habe den Eindruck, dass der obige Benchmark vernünftig ist, aber natürlich können feine Unterschiede zu den Anwendungsfällen in dieser Frage die Dinge beeinflussen! Wie ich spekuliere, kann es einen anfänglichen "bsxfun" Overhead geben, da es für große Arrays viel schneller ist. – Wolfie

+0

Wenn ich dies für den Bereich 1-10000 Zeilen ausführe, bekomme ich ein [verrauschtes Muster] (https: //i.stack. imgur/q2ym9.png), mit einem allgemeinen Vorteil für 'repmat'. Wenn ich es für 2-2^20 Bereich führe, erhalte ich das gleiche Ergebnis wie deines. – EBH

Verwandte Themen