Es gibt verschiedene Möglichkeiten, eine Matrix oder einen Vektor an eine beliebige, auch leere, Matrix anzuhängen. Vieles hängt von der Größe der Matrix ab und davon, wie oft Sie die Anfügung vornehmen wollen. (Beachten Sie, dass dünnbesetzte Matrizen etwas ganz anderes sind. Sie müssen gesondert behandelt werden.)
Das einfache Schema würde die Verkettung verwenden. Ich werde zum Beispiel ein zufälliges Array erstellen. Ich weiß zwar, dass ein Aufruf von rand hier die richtige Lösung wäre, aber ich mache es nur zu Vergleichszwecken.
n = 10000;
tic
A = [];
for i = 1:n
Ai = rand(1,3);
A = [A;Ai];
end
toc
Elapsed time is 9.537194 seconds.
Ich sehe, dass der Zeitaufwand ziemlich hoch war, viel höher als wenn ich Rand direkt angerufen hätte.
tic,rand(n,3);toc
Elapsed time is 0.008036 seconds.
Andere Möglichkeiten des Anhängens sind zeitlich ähnlich. Zum Beispiel können Sie auch durch Indizierung anhängen.
A = [];
A(end+1,:) = rand(1,3);
A
A =
0.91338 0.63236 0.09754
Dies ist vom Zeitaufwand her ähnlich wie das Anhängen durch Verkettung. Interessant ist die Tatsache, dass das Anhängen neuer Zeilen an ein Array sich von dem Anhängen neuer Spalten deutlich unterscheidet. Es dauert etwas länger, eine Zeile anzuhängen als eine Spalte. Dies liegt an der Art und Weise, wie Elemente in MATLAB gespeichert werden. Das Anhängen einer neuen Zeile bedeutet, dass die Elemente im Speicher tatsächlich neu gemischt werden müssen.
A = zeros(10000,3);
B = zeros(3,10000);
tic,for i = 1:100,A(end+1,:) = rand(1,3);end,toc
Elapsed time is 0.124814 seconds.
tic,for i = 1:100,B(:,end+1) = rand(3,1);end,toc
Elapsed time is 0.116209 seconds.
Das Problem bei jeder Append-Operation ist, dass MATLAB den für A benötigten Speicher neu zuweisen muss, und zwar JEDES Mal, wenn die Matrix größer wird. Da die Größe von A linear wächst, steigt die benötigte Gesamtzeit quadratisch mit n. Würden wir also die Größe von n verdoppeln, bräuchte das dynamisch gewachsene A viermal so lange zum Aufbau. Dieses quadratische Verhalten ist der Grund, warum man Ihnen rät, Ihre MATLAB-Arrays vorab zuzuweisen, wenn sie dynamisch erweitert werden. Wenn Sie sich die mlint-Flags im Editor ansehen, warnt MATLAB Sie, wenn dies der Fall ist.
Eine bessere Lösung, wenn Sie die endgültige Größe von A kennen, ist die Vorabzuweisung von A auf seine endgültige Größe. Dann indexieren Sie einfach hinein.
tic
A = zeros(n,3);
for i = 1:n
A(i,:) = rand(1,3);
end
toc
Elapsed time is 0.156826 seconds.
Dies ist zwar viel besser als die dynamisch gewachsenen Array, es ist immer noch viel schlechter als eine vektorisierte Verwendung von Rand. Also, wo immer möglich, verwenden Sie die vektorisierte Form von Funktionen wie diese.
Das Problem ist, dass man manchmal einfach nicht weiß, wie viele Elemente man am Ende haben wird. Es gibt noch einige Tricks, mit denen man das unangenehme quadratische Wachstum vermeiden kann.
Ein Trick besteht darin, die endgültige Größe von A zu schätzen. Verwenden Sie nun die Indizierung, um neue Werte in A einzufügen, aber achten Sie genau darauf, wann die neuen Einträge die Grenzen von A überschreiten werden. Kehren Sie nun zur Indizierung neuer Elemente in A zurück. Führen Sie eine separate Zählung durch, wie viele Elemente "angehängt" wurden. Am Ende dieses Prozesses löschen Sie die nicht verwendeten Elemente. Auf diese Weise lässt sich ein Großteil des unangenehmen quadratischen Verhaltens vermeiden, da nur wenige Anhängevorgänge durchgeführt werden. (Denken Sie daran, dass Sie die Größe von A verdoppeln, wenn Sie eine Anfügung vornehmen müssen).
Ein zweiter Trick ist die Verwendung von Zeigern. MATLAB bietet zwar nicht wirklich viele Möglichkeiten für Zeiger, aber ein Zell-Array ist ein Schritt in diese Richtung.
tic
C = {};
for i = 1:n
C{end+1} = rand(1,3);
end
A = cat(1,C{:});
toc
Elapsed time is 3.042742 seconds.
Dies nahm weniger Zeit in Anspruch als die gewachsene Anordnung. Warum? Wir haben nur ein Array mit Zeigern auf die Zellen erstellt. Das Schöne daran ist, dass es auch dann noch gut funktioniert, wenn jeder Append-Schritt eine variable Anzahl von Zeilen hat.
Ein Problem mit der Zelle Array, ist es nicht furchtbar effizient, wenn es MILLIONEN von Elementen, um anzuhängen sind. Es ist immer noch eine quadratische Operation, weil wir das Array von Zeigern bei jedem Schritt wachsen.
Eine Lösung für dieses Problem ist die Verwendung einer Mischung aus den beiden oben gezeigten Stilen. Definieren Sie also jede Zelle des Zellenfeldes als mäßig groß. Verwenden Sie nun die Indizierung, um neue Zeilen von A in die Zelle zu füllen. Wenn die aktuelle Zelle durch den nächsten Append-Schritt vergrößert werden muss, fügen Sie einfach eine neue Zelle zum Zellen-Array hinzu.
Vor einigen Jahren kam diese Diskussion in der MATLAB-Newsgroup auf, und es wurden mehrere Lösungen in dieser Richtung vorgeschlagen. Ich habe die Lösungen gepostet growdata & growdata2 als Dateien auf dem MATLAB Central File Exchange. Growdata2 verwendet Funktionshandles, um das Problem zu lösen:
tic
Ahandle = growdata2;
for i = 1:n
Ahandle(rand(1,3))
end
% unpack the object into a normal array
A = Ahandle();
toc
Elapsed time is 1.572798 seconds.
Zu dieser Zeit war es ein etwas schnellerer Ansatz, persistente Variablen zu verwenden.
tic
growdata
for i = 1:n
growdata(rand(1,3))
end
A = growdata;
toc
Elapsed time is 2.048584 seconds.
Seitdem hat sich die Implementierung von Funktionshandles in MATLAB deutlich verbessert, so dass das Funktionshandle nun schneller ist.
Ein Vorteil dieser Verfahren ist, dass sie keine quadratischen Leistungseinbußen mit sich bringen und gleichzeitig Millionen von Append-Schritten ermöglichen.
Nun gut, das sind sicherlich mehr Informationen, als ursprünglich bei der Fragestellung verlangt wurden. Aber vielleicht hat ja jemand etwas davon.