Ich habe es geschafft, Ihren Code in eine Zeile Code zu vektorisieren! Wenn man von ein paar Sekunden bis zu unter einer Millisekunde:
out = [0 0 AA(3:end) + ([1 2] * (diff(BB(hankel(1:3, 3:numel(BB)))) > 0)).*50011];
Um zu verstehen, wie man dorthin kommt, wollen wir schrittweise den ursprünglichen Code verbessern.
1)
Zuerst beginnen wir mit dem Doppel-Loop Sie haben:
tic
var0 = zeros(size(AA));
for i=3:numel(AA)
for j=1:N
if AA(i) == j && BB(i)<=BB(i-1) && BB(i-1)<=BB(i-2)
var0(i)=j;
else
if AA(i) == j && BB(i)<=BB(i-1) && BB(i-1)>BB(i-2)
var0(i)=j+50011;
else
if AA(i) == j && BB(i)>BB(i-1) && BB(i-1)<=BB(i-2)
var0(i)=j+2*50011;
else
if AA(i) == j && BB(i)>BB(i-1) && BB(i-1)>BB(i-2)
var0(i)=j+3*50011;
end
end
end
end
end
end
toc
2)
Wie @SpamBot erwähnt, die verschachtelte if/else-Anweisungen sein kann vereinfacht, indem man sie stattdessen verkettet. Außerdem werten Sie denselben Test AA(i)==j
mehrmals aus. Wenn der Test falsch ist, wird die gesamte for-Schleife übersprungen. So können wir diese zweite For-Schleife eliminieren und direkt j=AA(i)
verwenden.
Hier ist neu der Code:
tic
var1 = zeros(size(AA));
for i=3:numel(AA)
j = AA(i);
if BB(i)<=BB(i-1) && BB(i-1)<=BB(i-2)
var1(i) = j;
elseif BB(i)<=BB(i-1) && BB(i-1)>BB(i-2)
var1(i) = j + 50011;
elseif BB(i)>BB(i-1) && BB(i-1)<=BB(i-2)
var1(i) = j + 2*50011;
elseif BB(i)>BB(i-1) && BB(i-1)>BB(i-2)
var1(i) = j + 3*50011;
end
end
toc
Dies ist eine große Verbesserung, und der Code wird in einem Bruchteil der ursprünglichen Zeit. Noch können wir es besser machen ...
3)
Wie Sie in Ihrer Frage erwähnt, ist die if/else Bedingungen entsprechen dem Muster 00, 01, 10, 11
wo 0/1 oder falsch/wahr die Ergebnisse der Durchführung eines binär x> y teste über benachbarte Zahlen.
diese Idee verwenden, erhalten wir die folgenden Code:
tic
var2 = zeros(size(AA));
for i=3:numel(AA)
val = (BB(i) > BB(i-1)) * 10 + (BB(i-1) > BB(i-2));
switch (val)
case 00
k = 0;
case 01
k = 50011;
case 10
k = 2*50011;
case 11
k = 3*50011;
end
var2(i) = AA(i) + k;
end
toc
4)
Beginnen wir mit einem Tisch-Lookup-Operation, dass die Switch-Anweisung ersetzen.Dies gibt uns diese neue Version:
tic
v = [0 1 2 3] * 50011; % 00 01 10 11
var3 = zeros(size(AA));
for i=3:numel(AA)
var3(i) = AA(i) + v((BB(i) > BB(i-1))*2 + (BB(i-1) > BB(i-2)) + 1);
end
toc
5)
In dieser letzten Version, können wir mit der Feststellung ganz aus der Schleife loszuwerden, dass jede Iteration greift auf die Schicht BB(i-2:i)
in einer verschiebbares Fenster Weise. Wir können sauber use the hankel
function to create a sliding window über BB
(jeweils als eine Spalte zurückgegeben).
Als nächstes verwenden wir diff
, um vektorisierte Vergleiche durchzuführen, dann kartieren Sie das Ergebnis 0/1 der beiden Tests als [0 1 2 3]*50011
Werte. Zuletzt fügen wir den Vektor AA
passend hinzu.
Dies gibt uns unseren letzten Einzeiler, vollständig vektorisiert:
tic
var4 = [0, 0, AA(3:end) + ([1 2] * (diff(BB(hankel(1:3, 3:numel(BB)))) > 0)).*50011];
toc
Vergleich
die oben genannten Lösungen, um zu überprüfen, habe ich die folgenden Zufallsvektoren als Testdaten:
N = 50011;
AA = randi(N, [1 2000]);
BB = randi(N, [1 2000]);
assert(isequal(var0,var1,var2,var3,var4))
Ich bekomme die folgenden Zeiten zu den Lösungen in der angegebenen Reihenfolge:
Ich hoffe, dieser Beitrag war nicht zu lang, ich wollte nur zeigen, wie man diese Art von Problemen anpackt, indem man inkrementelle Änderungen vornimmt.
Nun nehmen Sie Ihre Wahl, bei der Lösung, die Sie am besten gefällt :)
Vielen Dank für Ihre unswer! Aber wenn ich deinen Vergleich verstanden habe (außer der ersten Version), benötigt die letzte Version mehr Zeit als die drei anderen !!! – bzak
Wir sprechen hier in der Größenordnung von unter einer Millisekunde, es gibt keinen signifikanten Unterschied ... Ich schlage vor, dass Sie mit der Lösung gehen, mit der Sie sich am wohlsten fühlen (Nummer 2 oben ist völlig in Ordnung). Ich gebe zu, in den Bereichen 3 bis 5 lag der Fokus eher auf einer kürzeren und vollständig vektorisierten Lösung als auf einer dramatischen Leistungsverbesserung. – Amro
Sie sehen hier im MATLAB-Tag, dass wir diese Art von Fragen oft als Herausforderung betrachten, um den kürzestmöglichen vektorisierten Code zu schreiben, der nicht immer den am besten lesbaren oder schnellsten bedeutet :) – Amro