2014-09-26 13 views
5

ho una cella in MATLAB cui ogni elemento contiene un vettore di lunghezza diversaConteggio righe uniche in una cella piena di vettori

esempio

C = {[1 2 3], [2 4 5 6], [1 2 3], [6 4], [7 6 4 3], [4 6], [6 4]} 

Come potete vedere, alcuni dei vettori sono ripetuti, altri sono unici.

Voglio contare il numero di volte in cui ogni vettore si verifica e restituire il conteggio in modo tale da poter popolare una tabella in una GUI in cui ogni riga è una combinazione univoca e la data mostra quante volte ciascuna combinazione si verifica.

ad es.

  Count 
"[1 2 3]"  2 
"[6 4]"  2 
"[2 4 5 6]" 1 
"[7 6 4 3]" 1 
"[4 6]"  1 

mi dovrebbe dire che l'ordine dei numeri in ciascun vettore è importante cioè [6 4] non è uguale a [4 6].

Qualche idea su come posso farlo in modo abbastanza efficiente?

Grazie a persone che hanno commentato finora. Come @Divakar ha gentilmente sottolineato, ho dimenticato di menzionare che i valori nel vettore possono essere più lunghi di una cifra. Ad esempio [46, 36 28]. Il mio codice originale concatenerebbe il vettore [1 2 3 4] a 1234 quindi utilizzare hist per eseguire il conteggio. Certamente questo cade a pezzi quando si arriva al di sopra di cifre singole, come si può notare la differenza tra [1, 2, 3, 4] e [12, 34].

+0

quando hai detto "in modo efficiente", intendi efficienza di runtime o qualcos'altro? – Divakar

+1

Sì - tempo di esecuzione veloce. La ragione è che dovrò applicarlo a celle molto grandi e quindi a molti vettori. :-) – Mark

risposta

6

È possibile convertire tutte le voci in carattere char e quindi in un array numerico 2D e infine utilizzare unique(...'rows') per ottenere etichette per righe univoche e utilizzarle per ottenere i relativi conteggi.

C = {[46, 36 28], [2 4 5 6], [46, 36 28], [6 4], [7 6 4 3], [4 6], [6 4]} %// Input 

char_array1 = char(C{:})-0; %// convert input cell array to a char array 
[~,unqlabels,entry_labels] = unique(char_array1,'rows'); %// get unique rows 
count = histc(entry_labels,1:max(entry_labels)); %// counts of each unique row 

Per lo scopo di presentare l'output in un formato come richiesto nella domanda, è possibile utilizzare questo -

out = [C(unqlabels)' num2cell(count)]; 

uscita -

out = 
    [1x4 double] [1] 
    [1x2 double] [1] 
    [1x2 double] [2] 
    [1x4 double] [1] 
    [1x3 double] [2] 

e visualizzare il righe univoche con celldisp -

ans{1} = 
    2  4  5  6 
ans{2} = 
    4  6 
ans{3} = 
    6  4 
ans{4} = 
    7  6  4  3 
ans{5} = 
    46 36 28 

Edit: Se si dispone di numeri negativi in ​​là, è necessario fare poco più lavoro per l'installazione char_array1 come mostrato qui e resto del codice rimane lo stesso -

lens = cellfun(@numel,C); 
mat1(max(lens),numel(lens))=0; 
mat1(bsxfun(@ge,lens,[1:max(lens)]')) = horzcat(C{:}); 
char_array1 = mat1'; 
+1

+1 Buono a sapersi che il comportamento di' char' è stato applicato su un array di celle. Si riempie automaticamente le colonne! –

+1

@LuisMendo Sì. Bene per l'efficienza si deve rapidamente passare dagli array di celle agli array numerici se possibile e fare ulteriori operazioni! Semplicemente non mi fido degli array di celle per implementazioni efficienti. – Divakar

+1

bel trucco con 'char', ma cosa fai se uno degli elementi della cella ha un valore negativo? per esempio 'C = {[46, -36, 28], ...'? – bla

3

Un modo mi viene in mente è quello di convertire in stringhe e quindi utilizzare unique

Cs = cellfun(@(x)(mat2str(x)),C,'uniformoutput',false); 
[Cu,idx_u,idx] = unique(Cs); 

Ora potete contare il numero di occorrenze con idx, per esempio utilizzando

fv=tabulate(idx) 

così fv, ha già tutte le informazioni che ti servono, ma per scopi di visualizzazione aggiungo:

[Cu' , num2cell(fv(:,2))] 

ans = 

'[1 2 3]'  [2] 
'[2 4 5 6]' [1] 
'[4 6]'  [1] 
'[6 4]'  [2] 
'[7 6 4 3]' [1] 
+0

questa risposta sarà valida per i casi di '1234' vs' [12 34] 'etc ... – bla

3

Un altro suggerimento che può pensare di convertire ogni array in una concatenazione di numeri, quindi fare un istogramma per contare quanti valori hai per voce. Dovremmo capire quanti numeri unici abbiamo per primi, che servirebbero come bordi dell'istogramma attraverso unique.

Una cosa ho bisogno da notare è che stiamo assumendo che ogni elemento nella propria matrice per ogni cella è una singola cifre . Questo ovviamente non funzionerà se ci sono numeri di due o più cifre.

In altre parole:

%// Convert each array of numbers into a single number 
numbers = cellfun(@(x) sum(x.*10.^(numel(x)-1:-1:0)), C); 
%// Find unique numbers 
uniNumbers = unique(numbers); 

%// Get histogram 
out = histc(numbers, uniNumbers); 

%// Display counts 
disp([uniNumbers; out]); 

out conterrebbe i conteggi per numero univoco nel cell matrice. Otteniamo:

 46   64   123  2456  7643 
     1   2   2   1   1 

Il trucco con la prima riga di codice è che sto usando la decomposizione dei numeri in base 10 in cui ogni cifra può essere rappresentato in modo univoco come somma di multipli di potenze di 10. Come tale , 4587 può essere rappresentato come:

4000 + 500 + 80 + 7 ==> 4*10^3 + 5*10^2 + 8*10^1 + 7*10^0 

presi ciascun numero nella nostra matrice, e usato come quelli coefficienti per ciascuna potenza decrescente di 10, allora tutti sommati insieme. Pertanto, negli array di celle, [1 2 3], viene convertito in 123 e così via. Con il vostro esempio, questo è l'uscita di numbers, che sta facendo quello che ho parlato sopra:

numbers = 

    Columns 1 through 6 

     123  2456   123   64  7643   46 

    Column 7 

      64 

paragonare questo con il tuo array di celle reale in C:

celldisp(C) 

C{1} = 
    1  2  3  
C{2} = 
    2  4  5  6 
C{3} = 
    1  2  3 
C{4} = 
    6  4 
C{5} = 
    7  6  4  3 
C{6} = 
    4  6 
C{7} = 
    6  4 
+0

Interessante mossa con quella conversione di numero singolo, ma faccio menzione del presupposto che ciò presuppone voci a cifra singola. wooah mi ha appena colpito, lo sto assumendo anche io! – Divakar

+0

@Divakar - Oh, giusto! Lo correggerò :) Grazie mille. – rayryeng

+0

Oh! Ben accennato @Divakar il mio esempio iniziale è stato un po 'scarso in quanto i numeri possono essere due cifre I.e. [49, 64, 25]. Il mio codice iniziale prevedeva torte a una cifra, ma quando sono andato oltre il 9 è andato tutto a pezzi! – Mark