2009-04-23 14 views
14

Mam kod MATLAB wstawiający n-wymiarowe punkty (n> 1) do macierzy (myPointMatrix) i mam myśli o tym, jak wstawić pierwszy punkt.Dołączanie wektora do pustej macierzy MATLABA

W tej chwili program sprawdza rozmiar myPointMatrix przed wstawieniem punktu. Jeśli jest to 1x1, to myPointMatrix jest ustawione na równe bieżącemu punktowi. W przeciwnym razie obecny punkt zostanie dołączony. To ustawienie if jest prawdziwe tylko raz, ale jest oceniane za każdym razem, gdy wstawiam punkt, który jest bardzo często.

Usunięcie if i próba dołączenia do myPointMatrix powoduje, że MATLAB w sposób zrozumiały narzeka, że ​​wymiary matrycy nie są spójne. Usunięcie zarówno wersji if, jak i inialization of myPointMatrix = 0 powoduje, że MATLAB będzie niezdefiniowany jako myPointMatrix. Również zrozumiałe.

Jak zainicjować myPointMatrix, aby można było usunąć if -zestaw? Czy jest jakieś inne inteligentne rozwiązanie?

myPointMatrix = 0; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      tempPoint = [x y z]; 
      if (length(myPointMatrix) == 1) 
       myPointMatrix = tempPoint; 
      else 
       myPointMatrix = [myPointMatrix; tempPoint]; 
      end 
     end 
    end 
end 

Odpowiedz

13

Użyj myPointMatrix = [];, aby zainicjować macierz.

Im większy myPointMatrix, tym wolniej będzie dołączane. Robi się wolniej i wolniej, ponieważ za każdym razem, gdy dodajesz punkt matlab, przydziela nową macierz nowego rozmiaru i kopiuje informacje ze starej macierzy + nowy punkt do nowej macierzy.

Następnie lepiej zainicjować MyPointMatrix z jego ostatecznym rozmiarem i wstawić punkty do podanych pozycji w macierzy.

+2

+1 za ostatnie zdanie. To jest najbardziej efektywny sposób na zainicjowanie macierzy w MATLAB. –

3

Najlepszym rozwiązaniem jest wstępne przyporządkowanie macierzy i użycie zmiennej pętli. To powinno być znacznie szybsze.

limit = 9; 
myPointMatrix = nan((limit+1)^3,3); 

loopVar = 1; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      myPointMatrix(loopVar,:) = [x y z]; 
      loopVar = loopVar + 1; 
     end 
    end 
end 
0

Uważam, że rozwiązanie szukasz jest zainicjować myPointMatrix do matrycy z 0 wierszy i 3 kolumn, tj

myPointMatrix = zeros(0, 3); 

Wtedy pierwszy przydział

myPointMatrix = [myPointMatrix; tempPoint]; 

będzie działać poprawnie, jak również kolejne. Równoważny sposób pisać przypisanie jest

myPointMatrix(end+1,:) = tempPoint; 

jednak pamiętać, niż rośnie matrycę tak nie jest skuteczna i, jak mówi AnnaR, inicjowanie myPointMatrix z IFS ostatecznej wielkości, jeśli jest znany, jest lepszym rozwiązaniem.

28

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.

0

To jest to, czego potrzebujesz

myPointMatrix=[]; 
for x=0:limit 
for y=0:limit 
for x=0:limit 
    myPointMatrix(:,end+1)=[x y z]; 
end 
end 
end 

ale tylko w przypadku, że można zrobić kilka operacji nieliniowej z [X Y Z], zanim ją przypisać. Jeśli nie, to można napisać powyższe linie w następujący sposób:

myPointMatrix=[]; 
myPointMatrix(1,:)=kron([1:limit],ones(1,limit^2)); 
myPointMatrix(2,:)=kron([1:limit^2],ones(1,limit)); 
myPointMatrix(3,:)=kron(ones(1,limit^2),[1:limit]); 

Powyższe jest całkowicie wektoryzowane, chociaż może chcieć edit kron.m i zastąpić niektóre find z logical ... ale można to zrobić samemu Przypuszczam .. .: D

0
%appending to matlab array "f": 

lfg=[697 770 852 941]; 
hfg=[1209 1336 1477]; 
f=[]; 
for i=1:4, 
    for j=1:3, 
     %f = [ f [lfg(i);hfg(j)] ]; 
     append(f , [lfg(i);hfg(j)]); 
    end 
end 
f 
Powiązane problemy