2013-09-04 31 views
6

Mentre scrivevo una sceneggiatura ho scoperto la funzione numpy.random.choice. L'ho implementato perché era molto più pulito dell'equivalente istruzione if. Tuttavia, dopo aver eseguito la sceneggiatura mi sono reso conto che è significativamente più lento di rispetto all'istruzione if.Perché random.choice è così lento?

Quanto segue è un MWE. Il primo metodo richiede 0,0 s, mentre il secondo richiede 7,2 s. Se scalate il ciclo i, vedrete quanto velocemente random.choice rallenta.

Qualcuno può commentare perché random.choice è molto più lento?

import numpy as np 
import numpy.random as rand 
import time as tm 

#------------------------------------------------------------------------------- 

tStart = tm.time() 
for i in xrange(100): 
    for j in xrange(1000): 
     tmp = rand.rand() 
     if tmp < 0.25: 
      var = 1 
     elif tmp < 0.5: 
      var = -1 
print('Time: %.1f s' %(tm.time() - tStart)) 

#------------------------------------------------------------------------------- 

tStart = tm.time() 
for i in xrange(100): 
    for j in xrange(1000): 
     var = rand.choice([-1, 0, 1], p = [0.25, 0.5, 0.25]) 
print('Time: %.1f s' %(tm.time() - tStart)) 
+3

Non è proprio un paragone equo. Ogni volta, numpy deve prendere la somma cumulativa della lista p, metterla in un nuovo vettore e quindi scorrere su di essa. Stai effettivamente facendo il pre-processo sapendo che ci sono solo tre variabili e che la somma del primo e del terzo è 0,5. Oltre a ciò, come indicato di seguito, numpy è ottimizzato per le operazioni vettorializzate, non per fare una singola operazione semplice migliaia di volte. –

+1

Inoltre, usa 'timeit', non' time' da solo. – Marcin

risposta

12

Si sta usando male. Vectorize l'operazione, o NumPy offrirà alcun beneficio:

var = numpy.random.choice([-1, 0, 1], size=1000, p=[0.25, 0.5, 0.25]) 

dati Timing:

>>> timeit.timeit('''numpy.random.choice([-1, 0, 1], 
...          size=1000, 
...          p=[0.25, 0.5, 0.25])''', 
...    'import numpy', number=10000) 
2.380380242513752 

>>> timeit.timeit(''' 
... var = [] 
... for i in xrange(1000): 
...  tmp = rand.rand() 
...  if tmp < 0.25: 
...   var.append(1) 
...  elif tmp < 0.5: 
...   var.append(-1) 
...  else: 
...   var.append(0)''', 
... setup='import numpy.random as rand', number=10000) 
5.673041396894519 
+2

+1 Questo è circa 7 volte più veloce del primo ciclo. –

+0

Come scritto, stai confrontando le mele con le mele? Il primo calcola 10^3 * 10^4 = 10^7 numeri casuali, ma il secondo calcola 10^2 * 10^3 * 10^4 = 10^9 numeri casuali, no? – DSM

+0

@DSM: Whoops. Copiato la cosa sbagliata al momento. Fixing ... – user2357112

1

ho il sospetto la generalità di np.random.choice sta rallentando verso il basso, a maggior ragione per i piccoli campioni di quelle grandi.

Un vettorializzazione greggio della versione if è:

def foo(n): 
    x = np.random.rand(n) 
    var = np.zeros(n) 
    var[x<.25] = -1 
    var[x>.75] = 1 
    return var 

Running in ipython ottengo:

timeit np.random.choice([-1,0,1],size=1000,p=[.25,.5,.25]) 
1000 loops, best of 3: 293 us per loop 

timeit foo(1000) 
10000 loops, best of 3: 83.4 us per loop 

timeit np.random.choice([-1,0,1],size=100000,p=[.25,.5,.25]) 
100 loops, best of 3: 11 ms per loop 

timeit foo(100000) 
100 loops, best of 3: 8.12 ms per loop 

Così, per la dimensione 1000, choice è 3-4x più lento, ma con i vettori più grandi , la differenza inizia a scomparire.

Problemi correlati