MATLAB trova e applica la funzione ai valori di indici ripetuti

Ho una matrice 352×11, indicizzata dalla colonna 1 con 10 punti dati. Alcuni dei valori dell’indice sono ripetuti. Mi piacerebbe trovare gli indici ripetuti e calcolare i punti dati medi per le prove ripetute (evitando i loop, se ansible).

Per esempio,

x = 26 77.5700 17.9735 32.7200 27 40.5887 16.6100 31.5800 28 60.4734 18.5397 33.6200 28 35.6484 27.2000 54.8000 29 95.3448 19.0000 37.7300 30 82.7273 30.4394 39.1400 

finire con:

 ans = 26 77.5700 17.9735 32.7200 27 40.5887 16.6100 31.5800 28 48.0609 22.8699 44.2150 29 95.3448 19.0000 37.7300 30 82.7273 30.4394 39.1400 

Stavo pensando se l’ho usato

 J = find(diff(x(:,1))==0); 

per trovare la posizione dei valori ripetuti, potrei quindi applicare la funzione alle posizioni corrispondenti di x , ma da dove comincio?

Puoi applicare accumarray a più colonne come mostrato qui

 labels = x(:,1) - min(x(:, 1)) + 1; labels = [repmat(labels(:),size(x,2),1), kron(1:size(x,2),ones(1,numel(labels))).']; totals = accumarray(labels,x(:),[], @mean); 

Questo è adattato dal codice di Gnovice .

Per farlo funzionare per il tuo codice allora devi eliminare tutti gli zeri nella parte anteriore

 totals(find(mean((totals == zeros(size(totals)))')), :) = []; 

quale risulta nel desiderato

  26.0000 77.5700 17.9735 32.7200 27.0000 40.5887 16.6100 31.5800 28.0000 48.0609 22.8699 44.2100 29.0000 95.3448 19.0000 37.7300 30.0000 82.7273 30.4394 39.1400 

Un approccio più generale dovrebbe utilizzare unique per trovare i valori dell’indice univoci:

 [U, ix, iu] = unique(x(:, 1)); 

e poi accumarray :

 [c, r] = meshgrid(1:size(x, 2), iu); y = accumarray([r(:), c(:)], x(:), [], @mean); 

Spiegazione

I valori di input da elaborare sono in realtà il secondo parametro di accumarray .

Il primo parametro di accumarray è una matrice, ogni riga è un insieme di indici nella matrice di output (accumulata) e corrisponde a un valore della riga corrispondente nel vettore indicato come secondo parametro.

Pensa all’output come a un array di celle. I secondi parametri sono i valori di input, e ogni riga del primo parametro indica in quale cella dell’accumulo della matrice di accumarray deve essere memorizzato il valore di input corrispondente. Quando l’output “cell array” è terminato, una funzione (nel nostro caso mean ) viene applicata a ciascuna cella.

Esempio

Ecco un breve esempio con una matrice più piccola:

 x = [27, 10, 8; 28, 20, 10; 28, 30, 50]; 

Troviamo i valori unici di:

 [U, ix, iu] = unique(x(:, 1)); 

Vector U memorizza i valori univoci, e iu indica quale indice del valore associato a ciascuna riga (si noti che in questa soluzione non abbiamo alcun uso per ix ). Nel nostro caso otteniamo che:

 U = 27 28 iu = 1 2 2 

Ora applichiamo accumarray :

 [c, r] = meshgrid(1:size(x, 2), iu); y = accumarray([r(:), c(:)], x(:), [], @mean); 

Il trucco elegante con meshgrid e [r(:), c(:)] produce un insieme di indici:

 [r(:), c(:)] = 1 1 2 1 2 1 1 2 2 2 2 2 1 3 2 3 2 3 

e questi sono gli indici per i valori di input x(:) , che è un equivalente vettore colonna di x :

 x(:) = 27 28 28 10 20 30 8 10 50 

Il processo di accumulazione:

  • Il primo valore 27 va alla cella <1,1> nella matrice di output.
  • Il secondo valore 28 va alla cella <2,1> nella matrice di uscita.
  • Il terzo valore 28 va alla cella <2,1> nella matrice di output.

Vedi cosa è appena successo? Entrambi i valori 28 vengono accumulati nella stessa cella (e alla fine verranno calcolati in media). Il processo continua:

  • Il quarto valore 10 va alla cella <1,2> ​​nella matrice di output.

e così via…

Una volta che tutti i valori sono memorizzati in celle, la funzione è applicata su ogni cella e otteniamo la matrice di output finale:

 y = 27 10 8 28 25 30 

Puoi trovare accumarray con @mean utile:

Supponendo che la prima colonna contenga i valori 1 .. k per alcuni k <= size(x,1) , puoi calcolare ogni colonna dell'output usando

 col = accumarray( x(:,1), x(:,2), [], @mean ); % second column 

Dato che hai inserito

 x = [ ... 26 77.5700 17.9735 32.7200; ... 27 40.5887 16.6100 31.5800; ... 28 60.4734 18.5397 33.6200; ... 28 35.6484 27.2000 54.8000; ... 29 95.3448 19.0000 37.7300; ... 30 82.7273 30.4394 39.1400]; 

È ansible creare una matrice di indici in cui le vgalue duplicate condividono lo stesso indice, utilizzando il terzo output di unique .

 %Get index of unique values (1 - N) [~, ~, ix] = unique(x(:,1)) 

Quindi è ansible utilizzare questo array per ribuild la matrice, combinando valori duplicati con la funzione desiderata.

 %Use accumarry to rebuild the matrix one column at a time result = [... accumarray( ix, x(:,1), [], @max ) ... %Many functions works here, as all inputs are the same. EG @mean, @max, @min accumarray( ix, x(:,2), [], @mean ) ... %Use mean to combine data, per problem statement. accumarray( ix, x(:,3), [], @mean ) ... accumarray( ix, x(:,4), [], @mean ) ... ]