2010-01-26 16 views
9

Lavorando in Matlab I ho 2 vettori di coordinate x con lunghezza diversa. Per esempio:Mappatura di 2 vettori - aiuto per vettorizzare

xm = [15 20 24 25 26 35 81 84 93]; 
xn = [14 22 26 51 55 59 70 75 89 96]; 

ho bisogno di mappare xm per xn, o in altre parole per trovare quale le coordinate nel xn sono più vicini a xm. Quindi se ho dei valori associati a quelle coordinate, posso usare questa mappa come indice e correlare questi valori.

Entrambi i vettori sono ordinati e non ci sono duplicati in ciascun vettore.

Ho scritto una semplice funzione con ciclo for:

function xmap = vectors_map(xm,xn) 
xmap = zeros(size(xm)); 
for k=1:numel(xm) 
    [~, ind] = min(abs(xm(k)-xn)); 
    xmap(k) = ind(1); 
end 

Per l'esempio di cui sopra è rendimenti

xmap = 
    1  2  2  3  3  3  8  9 10 

Funziona bene, ma richiede un po 'con lunghe vettori (oltre 100.000 punti) .

Qualche idea su come vettorializzare questo codice?

+0

Sto usando la nuova sintassi ~ nell'ultima versione di Matlab per saltare una variabile non utilizzata. Se hai una versione precedente, sostituisci ~ con tmp. – yuk

+1

Giusto per chiarire, vuoi per ogni xm [i] l'indice j tale che xm [i] è più vicino a xn [j]? –

+0

Sì. Buon riassunto, grazie. – yuk

risposta

5

Oh! Un'altra opzione: dal momento che stai cercando corrispondenze ravvicinate tra due elenchi ordinati, puoi passarli entrambi contemporaneamente, usando un algoritmo di tipo merge. Questo dovrebbe essere O (max (lunghezza (xm), lunghezza (xn))) - ish.


match_for_xn = zeros(length(xn), 1); 
last_M = 1; 
for N = 1:length(xn) 
    % search through M until we find a match. 
    for M = last_M:length(xm) 
    dist_to_curr = abs(xm(M) - xn(N)); 
    dist_to_next = abs(xm(M+1) - xn(N)); 

    if dist_to_next > dist_to_curr 
     match_for_xn(N) = M; 
     last_M = M; 
     break 
    else 
     continue 
    end 

    end % M 
end % N 

EDIT: commento vedere @ Yuk, il codice di cui sopra non è del tutto corretto!

+2

Ottimo! Questo codice mi dà oltre 50 volte il miglioramento della velocità con vettori di 10.000 lunghezze e 1500 (!) Volte con vettori da 100.000 litri. Può restituire un errore se diversi ultimi elementi di xn sono mappati su xm (fine). Ho appena cambiato le righe 6-7 a: se M yuk

+0

Sembra che non possa formattare il codice nei commenti. :( – yuk

+0

Cool! Yay! Sono contento che funzioni per te! Sì, è una delle cose divertenti dell'informatica, quando improvvisamente fai qualcosa di mille volte più veloce ... – rescdsk

1

Sembra che i vettori di input siano ordinati. Usa una ricerca binaria per trovare la corrispondenza più vicina. Questo ti darà un tempo di esecuzione O (n ln n).

+0

Forniresti del codice Matlab per favore? – yuk

+0

Sì, i vettori sono ordinati. – yuk

+0

Ah, ricerca binaria! Non ci ho pensato. +1 – John

0

xm e xn sono ordinati. Se questo è generalmente il caso, allora puoi fare molto meglio di passare l'intero array.

Per ciascun valore in xn, ci sarà un intervallo di valori per i quali un valore in xm sarà più vicino a quel numero rispetto a qualsiasi altro. Calcola preventivamente questi intervalli e puoi quindi passare attraverso entrambi gli array in sequenza.

0

Approfittando di essere ordinato, come dice David, sarà più veloce visto che hai così tanti punti, ma per riferimento un modo per vettorizzare questo sarebbe quello di utilizzare meshgrid:

[X Y] = meshgrid(xn, xm); 
diffs = X - y; 
mins = min(diffs, [], 2); 

Si noti che questo creerà due 100.000 x 100.000 matrici in memoria, quindi è probabilmente fattibile solo per i set di dati più piccoli.

+0

Sì, ci vuole molta memoria e molto più lentamente della mia funzione con piccoli vettori. – yuk

4

prendere in considerazione questa soluzione vettorizzati:

[~, xmap] = min(abs(bsxfun(@minus, xm, xn'))) 
+0

Bella vettorizzazione. Grazie. Tuttavia, è circa due volte più lento della mia funzione e richiede anche più memoria, ma meglio del codice precedente. – yuk

3

L'implementazione più rapida di cui sono a conoscenza che risolve questo problema è this one (codice C che può essere compilato come file .mex, per me è circa 20 volte più veloce del codice di rescdsk nella risposta accettata). È sorprendente che un'operazione così comune non sia una funzione incorporata di MATLAB.

+0

Grazie. Non l'ho ancora provato ma sembra una grande soluzione. – yuk