2013-04-26 11 views
6

Potrzebuję przetwarzać duże ilości danych tabelarycznych typu mieszanego - ciągi i duble. Standardowy problem, pomyślałbym. Jaka jest najlepsza struktura danych w Matlab do pracy z tym?Struktura danych Matlab dla typu mieszanego - ile czasu i przestrzeni jest wydajnych?

Cellarray zdecydowanie nie jest odpowiedzią. Jest to wyjątkowo nieefektywna pamięć. (testy pokazane poniżej). Zestaw danych (z przybornika statystyk) jest strasznie nieefektywny w czasie i przestrzeni. To pozostawia mnie z structarray lub strukturą tablic. Zrobiłem test na wszystkie cztery różne opcje zarówno dla czasu, jak i pamięci poniżej i wydaje mi się, że struktura macierzy jest najlepszą opcją dla rzeczy, które testowałem.

Jestem stosunkowo nowy w stosunku do Matlaba i to jest trochę rozczarowujące, szczerze mówiąc. W każdym razie - szukam porady, czy czegoś brakuje, czy moje testy są dokładne/uzasadnione. Czy brakuje mi innych kwestii poza dostępem/konwersją/użyciem pamięci, które prawdopodobnie pojawią się, gdy będę kodował więcej używając tych rzeczy. (używasz R2010b)

* * Test nr 1: Prędkość dostępu Dostęp do elementu danych.

cellarray:0.002s 
dataset:36.665s  %<<< This is horrible 
structarray:0.001s 
struct of array:0.000s 

* * testowy nr 2: szybkość konwersji i wykorzystanie pamięci rzuciłem zestaw danych z tego badania.

Cellarray(doubles)->matrix:d->m: 0.865s 
Cellarray(mixed)->structarray:c->sc: 0.268s 
Cellarray(doubles)->structarray:d->sd: 0.430s 
Cellarray(mixed)->struct of arrays:c->sac: 0.361s 
Cellarray(doubles)->struct of arrays:d->sad: 0.887s 
    Name   Size    Bytes Class  Attributes 
    c   100000x10   68000000 cell     
    d   100000x10   68000000 cell     
    m   100000x10    8000000 double    
    sac   1x1    38001240 struct    
    sad   1x1    8001240 struct    
    sc  100000x1    68000640 struct    
    sd  100000x1    68000640 struct 

================== KOD: TEST # 1

%% cellarray 
    c = cell(100000,10); 
    c(:,[1,3,5,7,9]) = num2cell(zeros(100000,5)); 
    c(:,[2,4,6,8,10]) = repmat({'asdf'}, 100000, 5); 
    cols = strcat('Var', strtrim(cellstr(num2str((1:10)'))))'; 
    te = tic; 
    for iii=1:1000 
     x = c(1234,5); 
    end 
    te = toc(te); 
    fprintf('cellarray:%0.3fs\n', te); 
    %% dataset 
    ds = dataset({ c, cols{:} }); 
    te = tic; 
    for iii=1:1000 
     x = ds(1234,5); 
    end 
    te = toc(te); 
    fprintf('dataset:%0.3fs\n', te); 
    %% structarray 
    s = cell2struct(c, cols, 2); 
    te = tic; 
    for iii=1:1000 
     x = s(1234).Var5; 
    end 
    te = toc(te); 
    fprintf('structarray:%0.3fs\n', te); 
    %% struct of arrays 
    for iii=1:numel(cols) 
     if iii/2==floor(iii/2) % even => string 
      sac.(cols{iii}) = c(:,iii); 
     else 
      sac.(cols{iii}) = cell2mat(c(:,iii)); 
     end 
    end 
    te = tic; 
    for iii=1:1000 
     x = sac.Var5(1234); 
    end 
    te = toc(te); 
    fprintf('struct of array:%0.3fs\n', te); 

============= ===== KOD: test # 2

%% cellarray 
% c - cellarray containing mixed type 
c = cell(100000,10); 
c(:,[1,3,5,7,9]) = num2cell(zeros(100000,5)); 
c(:,[2,4,6,8,10]) = repmat({'asdf'}, 100000, 5); 
cols = strcat('Var', strtrim(cellstr(num2str((1:10)'))))'; 
% c - cellarray containing doubles only 
d = num2cell(zeros(100000, 10)); 
%% matrix 
% doubles only 
te = tic; 
m = cell2mat(d); 
te = toc(te); 
fprintf('Cellarray(doubles)->matrix:d->m: %0.3fs\n', te); 
%% structarray 
% mixed 
te = tic; 
sc = cell2struct(c, cols, 2); 
te = toc(te); 
fprintf('Cellarray(mixed)->structarray:c->sc: %0.3fs\n', te); 
% doubles 
te = tic; 
sd = cell2struct(d, cols, 2); 
te = toc(te); 
fprintf('Cellarray(doubles)->structarray:d->sd: %0.3fs\n', te); 
%% struct of arrays 
% mixed 
te = tic; 
for iii=1:numel(cols) 
    if iii/2==floor(iii/2) % even => string 
     sac.(cols{iii}) = c(:,iii); 
    else 
     sac.(cols{iii}) = cell2mat(c(:,iii)); 
    end 
end 
te = toc(te); 
fprintf('Cellarray(mixed)->struct of arrays:c->sac: %0.3fs\n', te); 
% doubles 
te = tic; 
for iii=1:numel(cols) 
    sad.(cols{iii}) = cell2mat(d(:,iii)); 
end 
te = toc(te); 
fprintf('Cellarray(doubles)->struct of arrays:d->sad: %0.3fs\n', te); 
%% 
clear iii cols te; 
whos 
+0

podczas gdy 'dataset' jest rzeczywiście powolny, twój czas jest strasznie powolny. Dostaję 'dataset: 0.7s' na dostęp, podczas gdy inne są w tej samej kolejności, co twoje. Im działa R2013a na 32-bitowej WinXP – Amro

Odpowiedz

1

powiedziałbym, że jeśli trzeba zarządzać dużą ilość danych, a następnie MATLAB nie jest najlepszym wyborem na początek. Wybierz odpowiedni db i ewentualnie zaimportuj potrzebne dane do MATLAB.

Jednakże, jeśli planujesz używać MATLAB jakikolwiek bym jeszcze wybrać cellarrays, to znaczy, jeśli nie potrzebujemy składniowe odniesień do danych w formie fieldnames jak w struktur.

Korzystając z komórek, należy pamiętać, że każda komórka narzuca 112 bajtów narzutów. W związku z tym, chciałbym stworzyć komórkę dla każdej kolumny (nie komórkowy dla każdego skalarne podwójne):

c = cell(1,10); 
c(1,1:2:10) = num2cell(rand(1e5,5),1); 
c(1,2:2:10) = {cellstr(repmat('asdf', 100000, 1))}; 

i pamięci mądry (brak zmiany w czasie):

Name   Size    Bytes Class Attributes 
c    1x10   38000600 cell 

Ponadto, co nazywasz struktura macierzy jest zwykle określana strukturą "skalarną" w przeciwieństwie do tablicy struct (lub struktury niesarowej).

Jeśli poprawnie przypominam, struktura ma tendencję do obniżania wydajności odczytu/zapisu, gdy zaczniesz zagnieżdżać pola (muszę jednak znaleźć konkretny wątek).

3

Sposobem na sprawienie, by kod Matlab działał w przestrzeni i czasie, jest praca z dużymi tablicami prymitywów - to jest tablicami podwójnymi, intami lub znakami. Zapewnia to ściślejszy układ w pamięci i pozwala wykonywać operacje wektoryzacji.

W przypadku danych tabelarycznych każda kolumna ma być jednorodna pod względem typu, ale różne kolumny mogą być różnych typów, a zazwyczaj masz o wiele więcej wierszy niż kolumn. Często będziesz wykonywać operacje - porównania lub matematykę - nad wszystkimi elementami kolumny lub zamaskowany wybór kolumny, która nadaje się do operacji wektoryzacji. Przechowuj więc każdą kolumnę jako tablicę kolumn, mam nadzieję, prymitywów. Możesz przykleić te kolumny albo w polach struktury lub elementach wektora komórki; nie ma większego znaczenia pod względem wydajności, a formularz struktury będzie znacznie bardziej czytelny i będzie wyglądał bardziej jak tabela. Tablica 2-wymiarowa lub inna struktura danych, która przerywa wszystkie elementy w ich własnych małych mx-tablicach, nie będzie działać akuratnie.

Oznacza to, że jeśli masz tabelę 10 000 wierszy na 10 kolumn, chcesz mieć 10-cio macierzową macierz lub 10-polową strukturę, przy czym każde z tych pól lub elementów zawiera 10 000 długich prymitywnych wektorów kolumn.

Obiekt obiektu dataset jest w zasadzie owinięty wokół struktury tablic kolumn, jak opisano wcześniej, utknął w obiekcie. Ale obiekty w Matlab mają większy narzut niż zwykłe struktury i komórki; płacisz za jedno lub więcej wywołań metod przy każdym dostępie do niego. Spójrz na Is MATLAB OOP slow or am I doing something wrong? (pełne ujawnienie: to jedna z moich odpowiedzi).

Utworzony test nie świadczy o tym, jak dobry będzie kod Matlab, ponieważ wykonuje skalarny dostęp do jednego elementu. Oznacza to, że płaci za kolumnę, a następnie dostęp do elementu wiersza przy każdym przejściu przez pętlę. Jeśli twój kod Matlaba to robi, nie masz szczęścia. Aby być szybkim, musisz wyskoczyć z kolumn poza pętlą - to znaczy podnieś kosztowną operację dostępu do kolumny do zewnętrznej pętli lub kodu konfiguracji - a następnie wykonaj operacje wektorowe (jak +, ==, '<', ismember, i tak dalej) na całych wektorach kolumn lub pętli nad prymitywnymi wektorami numerycznymi (które JIT może zoptymalizować). Jeśli to zrobisz, wtedy dataset i inne struktury tabelaryczne oparte na obiektach mogą mieć przyzwoitą wydajność.

Struny w rodzaju Matlaba, ssą, niestety. Chcesz uciec od cellstrs. Masz kilka opcji.

  • Jeśli ciągi w kolumnie są o tej samej długości, a ty nie masz żadnych długich ciągów w nich można zapisać wektor ciągów jako 2-D char tablicy. Jest to pojedyncza ciągła tablica w pamięci i jest bardziej efektywna pod względem przestrzeni niż tablica komórek i może być szybsza dla operacji porównania i tak dalej. Jest to również jedna z natywnych reprezentacji napisanych przez Matlaba, więc normalne funkcje łańcuchowe będą z nią działać.
  • Jeśli łańcuchy mają niską liczność (tzn. Liczba odrębnych wartości jest mała w stosunku do całkowitej liczby elementów), można zakodować je jako "symbole", przechowując je jako tablicę prymitywnych intów, które są indeksami w do listy różnych wartości ciągu. Funkcja unique imoże pomóc w implementacji tych kodowań. Tak długo, jak robisz testy równości i nie sortujesz, te zakodowane kolumny ciągów będą działały z prędkością numeryczną.
  • Wierzę, że jeden z zestawów narzędzi, może ten z dataset, obsługuje zmienne "klasyfikator" lub "kategoryczne", które są w zasadzie gotową implementacją kodowania o niskiej liczności.
  • Nie przejmuj się ciągami Java; obciążenie związane z przekroczeniem bariery Matlab-to-Java spowoduje stratę netto.
  • Mam nadzieję, że ktoś wymyślił coś jeszcze.

Jeśli musisz trzymać się cellstrów, przechowuj je jako wektory kolumnowe wewnątrz struktury, jak opisano powyżej; w ten sposób płacisz tylko za dostęp do komórki, gdy faktycznie pracujesz w kolumnie z ciągami znaków.

+0

+1 dobrze wyjaśnione i wnikliwe odpowiedzi. Również problem napowietrznych OOP zdecydowanie poprawił wydajność. Na przykład dostaję 0,7 s dla dostępu do zestawu danych w tym teście (w R2013a) w porównaniu z 36 sekundą PO zgłosił – Amro

+0

Oczywiście wciąż jest miejsce na ulepszenia. Byłoby interesujące, gdybyś mógł zaktualizować wyniki testu porównawczego, jeśli masz dostęp do najnowszej wersji – Amro

+0

Dzięki. Tak, ulepszanie dźwięków to dobry pomysł. Wydajność poza OOP również powinna się poprawić. Obawiam się, że ktoś inny będzie musiał dokonać zaktualizowanego testu porównawczego - zmieniłem pracę i obecnie nie mam licencji Matlab. –