2015-02-25 5 views
21

Sto cercando di trovare il modo più veloce per standardizzare una matrice in Matlab (colonne di varianza unità media e zero). Tutto si riduce a quale sia il modo più rapido per applicare la stessa operazione a tutte le righe di una matrice. Ogni post che ho letto arriva alla stessa conclusione: utilizza bsxfun invece di repmat. Questo articolo, scritto da Mathworks è un esempio: http://blogs.mathworks.com/loren/2008/08/04/comparing-repmat-and-bsxfun-performance/Matlab - bsxfun non è più veloce di repmat?

Tuttavia, quando si cerca questo sul mio computer repmat è sempre più veloce. Qui sono i miei risultati utilizzando lo stesso codice in questo articolo:

m = 1e5; 
n = 100; 
A = rand(m,n); 

frepmat = @() A - repmat(mean(A),size(A,1),1); 
timeit(frepmat) 

fbsxfun = @() bsxfun(@minus,A,mean(A)); 
timeit(fbsxfun) 

Risultati:

ans = 

    0.0349 


ans = 

    0.0391 

In realtà, non riesco mai a ottenere bsxfun di svolgere meglio di repmat in questa situazione, non importa quanto piccolo o grande è la matrice di input.

Qualcuno può spiegarlo?

+1

Per me l'approccio bsxfun è sempre più veloce, anche per gli array più grandi. (Matlab 2014a) – thewaywewalk

+0

Per me (R2014b) vince anche bsxfun. Quale versione di matlab usi? –

+0

L'ho provato sia nel 2014 che nel 2014b. Il sistema operativo utilizzato potrebbe fare la differenza? Sono su OSX. – user1337

risposta

11

La maggior parte dei consigli che stai leggendo, incluso il post sul blog di Loren, si riferisce probabilmente alle vecchie versioni di MATLAB, per le quali bsxfun era un po 'più veloce di repmat. In R2013b (vedere la sezione "Prestazioni" nel collegamento), repmat è stato reimplementato per fornire grandi miglioramenti delle prestazioni quando applicato a argomenti numerici, char e logici. Nelle versioni recenti, può avere all'incirca la stessa velocità di bsxfun.

Per quel che vale, sulla mia macchina con R2014a ricevo

m = 1e5; 
n = 100; 
A = rand(m,n); 

frepmat = @() A - repmat(mean(A),size(A,1),1); 
timeit(frepmat) 

fbsxfun = @() bsxfun(@minus,A,mean(A)); 
timeit(fbsxfun) 

ans = 
     0.03756 
ans = 
    0.034831 

modo che appaia come bsxfun è ancora un pochino più veloce, ma non molto - e sulla vostra macchina sembra il contrario è il caso . Naturalmente, è probabile che questi risultati varieranno di nuovo, se si modifica la dimensione di A o l'operazione che si sta applicando.

Ci possono essere altri motivi per preferire una soluzione rispetto all'altra, come l'eleganza (preferisco lo bsxfun, se possibile).


Edit: commentatori hanno chiesto per un motivo specifico per preferire bsxfun, il che implica che si potrebbe utilizzare meno memoria di repmat evitando una copia temporanea che repmat non lo fa.

Non penso che questo sia effettivamente il caso. Ad esempio, aprire Task Manager (o l'equivalente in Linux/Mac), guardare i livelli di memoria, e il tipo:

>> m = 1e5; n = 8e3; A = rand(m,n); 
>> B = A - repmat(mean(A),size(A,1),1); 
>> clear B 
>> C = bsxfun(@minus,A,mean(A)); 
>> clear C 

(Regolare m e n fino a quando i salti sono visibili nel grafico, ma non così grande che si esaurito la memoria).

vedo esattamente lo stesso comportamento sia repmat e bsxfun, che è quella memoria aumenta gradualmente verso il nuovo livello (sostanzialmente raddoppiare la dimensione A) senza ulteriore picco temporaneo.

Questo vale anche se l'operazione viene eseguita sul posto.Ancora una volta, guardare la memoria e tipo:

>> m = 1e5; n = 8e3; A = rand(m,n); 
>> A = A - repmat(mean(A),size(A,1),1); 
>> clear all 
>> m = 1e5; n = 8e3; A = rand(m,n); 
>> A = bsxfun(@minus,A,mean(A)); 

nuovo, vedo esattamente lo stesso comportamento sia repmat e bsxfun, che è che la memoria raggiunge un picco (sostanzialmente raddoppiare la dimensione A), e poi ricade al livello precedente.

Quindi temo di non vedere molte differenze tecniche in termini di velocità o memoria tra repmat e bsxfun. La mia preferenza per bsxfun è in realtà solo una preferenza personale in quanto sembra un po 'più elegante.

+1

'bsxfun' ha ancora il vantaggio di utilizzare meno memoria, poiché evita internamente la ripetizione dei dati, sono corretto? Voglio dire, dare una ragione per giustificare la preferenza per 'bsxfun'! :-) –

+0

@LuisMendo è possibile la reimplementazione di 'repmat' evita la copia esplicita della memoria? È possibile implementare una copia "pigra"? Non ho accesso alle versioni recenti di Matlab ... – Shai

+0

@Shai Sì, questo è ciò che intendevo con la mia domanda. Potrebbe essere che 'repmat' internamente compia un qualche tipo di ottimizzazione. Non lo so. Ma preferisco ancora 'bsxfun'! –