Istnieje kilka sposobów dołączania macierzy lub wektora do dowolnej macierzy, pustej lub nie. Wiele zależy od rozmiaru matrycy i od tego, jak często będziesz ją uzupełniał. (Zauważ, że rzadkie macierze są zupełnie innymi zwierzętami, które trzeba traktować osobno.)
Prosty schemat użyłby konkatenacji. Na przykład utworzę losową tablicę. Chociaż wiem, że jedno połączenie z Randem byłoby właściwym rozwiązaniem, robię to tylko w celach porównawczych.
n = 10000;
tic
A = [];
for i = 1:n
Ai = rand(1,3);
A = [A;Ai];
end
toc
Elapsed time is 9.537194 seconds.
Zobacz, że czas wymagany był stosunkowo wysoki, znacznie więcej, niż po prostu nazywa rand bezpośrednio.
tic,rand(n,3);toc
Elapsed time is 0.008036 seconds.
Inne sposoby dołączania są podobne w czasie. Na przykład możesz dołączyć także poprzez indeksowanie.
A = [];
A(end+1,:) = rand(1,3);
A
A =
0.91338 0.63236 0.09754
Będzie to podobne pod względem czasu do dołączenia przez konkatenację. Interesującym faktem jest to, że dodanie nowych wierszy do tablicy jest nieco inne niż dodawanie nowych kolumn. Trwa nieco więcej czasu, aby dodać wiersz niż kolumnę. Jest tak ze względu na sposób przechowywania elementów w MATLAB. Dołączanie nowego wiersza oznacza, że elementy muszą być faktycznie przetasowane w pamięci.
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.
Problem z każdej operacji dodawania w ogóle jest to, że MATLAB należy przydzielić pamięć wymaganą do A, i to za każdym razem podłoże rośnie wielkość. Ponieważ rozmiar litery A rośnie liniowo, wymagany całkowity czas rośnie z n. Tak więc, gdybyśmy podwoili wielkość n, dynamicznie uprawiana A zajmie cztery razy więcej czasu. To kwadratowe zachowanie powoduje, że ludzie zalecają wstępne przydzielenie macierzy MATLAB, gdy będą one dynamicznie wzrastać. W rzeczywistości, jeśli spojrzysz na flagi mlint w edytorze, MATLAB ostrzega cię, gdy widzi to.
Lepszym rozwiązaniem, jeśli znasz ostateczny rozmiar A, jest wstępne przydzielenie A do jego ostatecznego rozmiaru. Wtedy właśnie indeks w.
tic
A = zeros(n,3);
for i = 1:n
A(i,:) = rand(1,3);
end
toc
Elapsed time is 0.156826 seconds.
Chociaż jest to znacznie lepiej niż dynamicznie uprawianych tablicy, nadal jest o wiele gorsza niż vectorized użycia rand. Jeśli to możliwe, używaj wektorowej formy takich funkcji.
Problem polega na tym, że czasami po prostu nie wiesz, ile elementów otrzymasz. Istnieje wciąż kilka sztuczek, których można użyć, aby uniknąć paskudnego, kwadratowego wzrostu.
Jedną z nich jest odgadnięcie ostatecznego rozmiaru A. Teraz użyj indeksowania, aby wstawić nowe wartości do A, ale uważnie obserwuj, kiedy nowe wpisy będą się rozlewać poza granice A. Kiedy jest to prawie wszystko Zdarzyć się, PODWÓJ rozmiar A, dołączając jeden duży blok zer do końca. Teraz powróć do indeksowania nowych elementów w A. Zachowaj oddzielną liczbę elementów, które zostały "dołączone". Na samym końcu tego procesu usuń nieużywane elementy. Pozwala to uniknąć wielu nieprzyjemnych, kwadratowych zachowań, ponieważ tylko kilka dołączonych kroków zostanie kiedykolwiek zrobionych. (Pamiętaj, że podwajasz rozmiar A, kiedy musisz zrobić dodatek).
Drugą sztuczką jest użycie wskaźników. Podczas gdy MATLAB tak naprawdę nie oferuje wiele możliwości w zakresie wskaźników, tablica komórek jest krokiem w tym kierunku.
tic
C = {};
for i = 1:n
C{end+1} = rand(1,3);
end
A = cat(1,C{:});
toc
Elapsed time is 3.042742 seconds.
Miało to mniej czasu do osiągnięcia niż uprawianych tablicy. Czemu? Budowaliśmy tylko komórki wskaźników. Dobrą rzeczą jest to, że jeśli każdy krok dołączania ma zmienną liczbę wierszy, nadal działa ładnie.
Problem z macierzą komórek, czy nie jest strasznie wydajny, gdy jest MILIONY elementów do dodania. Wciąż jest to jednak operacja kwadratowa, ponieważ na każdym etapie rozwijamy zestaw wskaźników.
Rozwiązaniem tego problemu jest użycie amalgamatu dwóch powyższych stylów. W ten sposób określ każdą komórkę macierzy komórkowej jako umiarkowanie dużą.Teraz użyj indeksowania, aby dodać nowe wiersze A do komórki. Gdy obecna komórka musi zostać powiększona o następny krok dołączania, po prostu dodaj nową komórkę do tablicy komórek.
Kilka lat temu dyskusja ta pojawiła się na grupie dyskusyjnej MATLAB i zaproponowano kilka rozwiązań w tym zakresie. Opublikowałem rozwiązania growdata & growdata2 jako pliki na centralnej bazie danych MATLAB. Growdata2 wykorzystywane funkcja obsługuje do rozwiązania problemu:
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.
W tym czasie było to nieco szybciej podejście używać zmiennych trwałe.
tic
growdata
for i = 1:n
growdata(rand(1,3))
end
A = growdata;
toc
Elapsed time is 2.048584 seconds.
Od tego czasu implementacja uchwytów funkcji wyraźnie poprawiła się w MATLAB, więc uchwyt funkcji jest teraz szybszy.
Zaletą tych systemów jest to, że nie mają one kwadratowej kary za wydajność, a jednocześnie pozwalają na miliony dodanych kroków.
No cóż, to z pewnością więcej informacji niż pierwotnie zażądano, gdy zadano pytanie. Być może ktoś coś z tego wyciągnie.
+1 za ostatnie zdanie. To jest najbardziej efektywny sposób na zainicjowanie macierzy w MATLAB. –