2013-07-30 19 views
11

Ci sono a few articles che mostrano che MATLAB preferisce le operazioni su colonna rispetto alle operazioni di riga e che, a seconda di come si dispongono i dati, le prestazioni can vary significantly. Ciò è apparentemente dovuto al fatto che MATLAB utilizza un ordine column-major per rappresentare gli array.Prestazioni delle operazioni riga contro colonna in NumPy

Ricordo di aver letto che Python (NumPy) utilizza un ordine row-major. Con questo, le mie domande sono:

  1. Si può prevedere una differenza simile in termini di prestazioni quando si lavora con NumPy?
  2. Se la risposta a quanto sopra è sì, quali sarebbero alcuni esempi che evidenziano questa differenza?
+0

Si potrebbe voler controllare [questo] (http://stackoverflow.com/questions/17840661). È un esempio recente in cui vi è una grande differenza nelle operazioni su diversi assi. Anche se questo potrebbe essere un bug. – Daniel

risposta

11

Come molti parametri di riferimento, ciò dipende molto dai dettagli della situazione. È vero che, per impostazione predefinita, numpy crea array in ordine C contiguo (riga maggiore), quindi, in astratto, le operazioni di scansione su colonne dovrebbero essere più veloci di quelle che eseguono la scansione su righe. Tuttavia, la forma dell'array, le prestazioni dell'ALU e la cache sottostante sul processore hanno un impatto enorme sui particolari.

Ad esempio, sul mio MacBook Pro, con un piccolo numero intero o float matrice, i tempi sono simili, ma una piccola tipo intero è notevolmente inferiore al tipo float:

>>> x = numpy.ones((100, 100), dtype=numpy.uint8) 
>>> %timeit x.sum(axis=0) 
10000 loops, best of 3: 40.6 us per loop 
>>> %timeit x.sum(axis=1) 
10000 loops, best of 3: 36.1 us per loop 

>>> x = numpy.ones((100, 100), dtype=numpy.float64) 
>>> %timeit x.sum(axis=0) 
10000 loops, best of 3: 28.8 us per loop 
>>> %timeit x.sum(axis=1) 
10000 loops, best of 3: 28.8 us per loop 

Con matrici più grandi del assoluti differenze diventano più grandi, ma almeno sulla mia macchina sono ancora più piccola per il tipo di dati più grande:

>>> x = numpy.ones((1000, 1000), dtype=numpy.uint8) 
>>> %timeit x.sum(axis=0) 
100 loops, best of 3: 2.36 ms per loop 
>>> %timeit x.sum(axis=1) 
1000 loops, best of 3: 1.9 ms per loop 

>>> x = numpy.ones((1000, 1000), dtype=numpy.float64) 
>>> %timeit x.sum(axis=0) 
100 loops, best of 3: 2.04 ms per loop 
>>> %timeit x.sum(axis=1) 
1000 loops, best of 3: 1.89 ms per loop 

Si può dire NumPy per creare un array (column-major) Fortran contiguo utilizzando l'argomento order='F' parola chiave per numpy.asarray, numpy.ones, numpy.zeros e simili, o convertendo un array esistente usando numpy.asfortranarray. Come previsto, questo ordinamento scambia l'efficienza delle operazioni di riga o colonna:

in [10]: y = numpy.asfortranarray(x) 
in [11]: %timeit y.sum(axis=0) 
1000 loops, best of 3: 1.89 ms per loop 
in [12]: %timeit y.sum(axis=1) 
100 loops, best of 3: 2.01 ms per loop 
0

Sospetto che sarà diverso a seconda dei dati e delle operazioni.

La risposta più semplice è quello di scrivere alcuni test utilizzando la stessa, mondo reale, i dati del genere che si sta pensando di usare e le funzioni che si sta pensando di usare e quindi utilizzare cprofile o timeit per confrontare le velocità, per la vostra operazioni, a seconda di come strutturate i vostri dati.

2
In [38]: data = numpy.random.rand(10000,10000) 

In [39]: %timeit data.sum(axis=0) 
10 loops, best of 3: 86.1 ms per loop 

In [40]: %timeit data.sum(axis=1) 
10 loops, best of 3: 101 ms per loop 
Problemi correlati