2015-08-24 10 views
6

accumarray utilizza due file di indici per creare una matrice con elementi sulla posizione delle coppie di indice validi con un valore assegnato dalla funzione specificata, ad esempio:Lasciando accumarray uscita un tavolo

A = [11:20]; 
B = flipud([11:20]); 
C = 1:10; 
datamatrix = accumarray([A B],C); 

questo modo datamatrix sarà una matrice 20x20 con valori. Se i valori di A e B tuttavia sono molto grandi, questo si tradurrà in una matrice per lo più vuota, con una piccola serie di dati nell'angolo più lontano. Per aggirare questo, si potrebbe impostare accumarray a issparse:

sparsedatamatrix = accumarray([A B],C,[],@sum,[],true); 

Questo farà risparmiare un sacco di memoria in caso min(A) e/o min(B) è/sono molto grandi.

mio problema, tuttavia, è che ho una matrice Mx7, con M~1e8, su cui voglio raccogliere i mezzi di colonne tre a sette sulla base indicizzazione nelle prime due colonne e la deviazione standard della terza colonna basata sul terzo così:

result = accumarray([data(:,1) data(:,2)],data(:,3),[],@std); 

voglio salvare questo ritorno in una tabella, strutturato come [X Y Z std R G B I], dove X e Y sono gli indici, Z è l'altezza media di quel pixel, R, G, B e I sono valori medi (colore e intensità) per pixel e std è la deviazione standard delle altezze (ad es. la ruvidità). L'utilizzo di issparse in questo caso non aiuta, poiché trasformo le matrici risultanti da accumarray utilizzando repmat.

Il punto di questo codice è di stimare l'altezza, la rugosità, il colore e l'intensità di un pezzo di terra da una nuvola di punti. Ho arrotondato le coordinate in X e Y per creare una griglia e ora ho bisogno di quei valori medi per cella della griglia, ma ho l'output come una "tabella" (non il tipo di dati MATLAB, ma un array 2D che non è l'output matrice predefinito).

Quindi, per concludere con la domanda:

C'è un modo per accumarray o una funzione simile a questa tabella di uscita senza (potenzialmente molto grande) matrice intermedia?

codice qui sotto:

Xmax = max(Originaldata(:,1)); 
Ymax = max(Originaldata(:,2)); 
X_avg_grid=(Edgelength:Edgelength:Xmax*Edgelength)+Xorig; 
TestSet = zeros(Xmax*Ymax,9); 

xx = [1:length(X_avg_grid)]'; %#ok<*NBRAK> 
TestSet(:,1) = repmat(xx,Ymax,1); 
ll = 0:Xmax:Xmax*Ymax; 
for jj = 1:Ymax 
    TestSet(ll(jj)+1:ll(jj+1),2) = jj; 
end 

for ll = 1:7 
    if ll == 2 
     tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@std); 
     tempdat = reshape(tempdat,[],1); 
     TestSet(:,ll+2) = tempdat; 
    elseif ll == 7 
     tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],1); 
     tempdat = reshape(tempdat,[],1); 
     TestSet(:,ll+2) = tempdat; 
    elseif ll == 1 
     tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@mean); 
     tempdat = reshape(tempdat,[],1); 
     TestSet(:,ll+2) = tempdat; 
    else 
     tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,ll+1),[],@mean); 
     tempdat = reshape(tempdat,[],1); 
     TestSet(:,ll+2) = tempdat; 
    end 
end 

TestSet = TestSet(~(TestSet(:,9)==0),:); 

nona colonna qui è solo la quantità di punti per cellula.

Originaldata = 
19 36 2.20500360107422 31488 31488 31488 31611 
20 37 2.26400360107422 33792 33792 34304 33924 
20 37 2.20000360107422 33536 33536 34048 33667 
19 36 2.20500360107422 34560 34560 34560 34695 
20 36 2.23300360107422 32512 32512 33024 32639 
21 38 2.22000360107422 31744 31488 33024 31611 
21 37 2.20400360107422 32512 32768 33792 32896 
21 37 2.24800360107422 29696 29440 30720 29555 
21 38 2.34800360107422 32768 32768 32768 32639 
21 37 2.23000360107422 33024 33024 33536 33153 

Quindi tutti i punti della stessa X, Y (ad esempio [19 36] o [21 37]) sono mediati (altezza, RGB, intensità in questo ordine) e dei valori nella terza colonna della deviazione standard è anche desiderata:

Result = 
19 36 2.2050036 0.00  33024 33024 33024  33153 
21 37 2.227336934 0.02212088 31744 31744 32682.66 31868 

e così via per il resto dei dati.

Ho aggiornato il mio codice all'ultima versione che ho. Questa memoria ridotta in testa un po ', poiché ora la funzione crea le griglie una dopo l'altra anziché tutte in una volta. Tuttavia, il codice è in esecuzione in parallelo, quindi ci sono ancora otto griglie simultanee create, quindi una soluzione sarebbe comunque apprezzata.

+1

Non sono sicuro di seguirlo. Se vuoi fare come 'accumarray' fa solo sommare _rows_ invece di numeri, puoi usare (sparse) la moltiplicazione della matrice come in [questo Q & A] (http://stackoverflow.com/questions/29906059/summing-rows-by- index-using-accumarray) –

+0

Non posso usare sparse() poiché non supporta altre funzioni oltre alla sua "somma" nativa e non può fare accumarray fuori da una matrice sparsa, dal momento che repmat non può funzionare con gli spars. – Adriaan

+1

Ho la sensazione che ciò che si desidera _can_ venga eseguito con una moltiplicazione di matrice sparsa. Ma dovresti creare un esempio minimo e funzionante con input e output desiderati; la tua domanda così com'è non è molto chiara –

risposta

3

Uno schizzo di una soluzione che utilizza indici lineari e matrici sparse 2D

lind = Originaldata(:,1) + max(Originaldata(:,1)) * (Originaldata(:,2) - 1); 
daccum(7,:) = accumarray(lind, 1, [], @sum, [], true); %// start with last one to pre-allocate all daccum 
daccum(1,:) = accumarray(lind, Originaldata(:,3), [], @mean, [], true); 
daccum(2,:) = accumarray(lind, Originaldata(:,3), [], @std, [], true); 
daccum(3,:) = accumarray(lind, Originaldata(:,4), [], @mean, [], true); 
daccum(4,:) = accumarray(lind, Originaldata(:,5), [], @mean, [], true); 
daccum(5,:) = accumarray(lind, Originaldata(:,6), [], @mean, [], true); 
daccum(6,:) = accumarray(lind, Originaldata(:,7), [], @mean, [], true); 

Ora è possibile ottenere solo quello che serve

inter = [Originaldata(:,1), Originaldata(:,2), full(daccum(:,lind))' ]; 
1

si potrebbe pre-processo i dati.

Una cosa che si può ottenere in questo modo è rimuovere le righe indesiderate (come quelle aventi due o meno occorrenze) in modo che non si ha a che fare con 0 deviazione standard:

%// Count occurences: 
combined_coord = Originaldata(:,1)*1E6+Originaldata(:,2); %// "concatenating" the coords 
[C,~,ic] = unique(combined_coord); 
occurences = [C accumarray(ic,1)]; 
%// Find all points that have <=2 occurences: 
coords_to_remove = occurences((occurences(:,2)<=2),1); 
%// Find valid lines: 
valid_lns = ~sum(bsxfun(@eq,combined_coord,coords_to_remove'),2); %' 
%// Filter original data: 
new_data = Originaldata(valid_lns,:); 
2

è possibile utilizzare prima unique con l'opzione 'rows' per trovare gli indici delle coppie uniche di coordinate X e Y, quindi utilizzare questi indici come input di pedice nelle chiamate a accumarray (dovrai chiamarlo separatamente per ogni colonna, poiché accumarray non funziona t gestire gli ingressi matrix):

[xyPairs, ~, index] = unique(Originaldata(:, 1:2), 'rows'); 
nPairs = max(index); 
Result = [xyPairs ... 
      accumarray(index, Originaldata(:, 3), [nPairs 1], @mean) ... 
      accumarray(index, Originaldata(:, 3), [nPairs 1], @std) ... 
      accumarray(index, Originaldata(:, 4), [nPairs 1], @mean) ... 
      accumarray(index, Originaldata(:, 5), [nPairs 1], @mean) ... 
      accumarray(index, Originaldata(:, 6), [nPairs 1], @mean) ... 
      accumarray(index, Originaldata(:, 7), [nPairs 1], @mean) ... 
      accumarray(index, ones(size(index)), [nPairs 1], @sum)];