2013-09-04 14 views
6

Beim Schreiben eines Skripts habe ich die Funktion numpy.random.choice entdeckt. Ich habe es implementiert, weil es viel sauberer war als die äquivalente if-Anweisung. Nach dem Ausführen des Skripts stellte ich jedoch fest, dass es wesentlich langsamer ist als die if-Anweisung.Warum ist random.choice so langsam?

Folgendes ist ein MWE. Die erste Methode dauert 0,0 s, während die zweite 7,2 s dauert. Wenn Sie die i Schleife vergrößern, sehen Sie, wie schnell random.choice langsamer wird.

Kann jemand kommentieren, warum random.choice so viel langsamer ist?

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

Das ist nicht wirklich ein fairer Vergleich. Jedes Mal muss numpy die kumulative Summe der p-Liste nehmen, diese in einen neuen Vektor einfügen und dann darüber iterieren. Sie tun effektiv Vorverarbeitung, indem Sie wissen, dass es nur drei Variablen gibt, und dass die Summe der ersten und dritten .5 ist. Darüber hinaus ist numpy, wie unten erwähnt, für vektorisierte Operationen optimiert, nicht für eine einfache Operation tausendfach. –

+1

Verwenden Sie auch "Zeit", nicht "Zeit" für sich. – Marcin

Antwort

12

Sie verwenden es falsch. Vektorisiert den Betrieb oder numpy wird keinen Nutzen bieten:

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

Timing-Daten:

>>> 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 Dies ist etwa 7x schneller als die erste Schleife. –

+0

Wie geschrieben, vergleichen Sie Äpfel mit Äpfeln? Der erste berechnet 10^3 * 10^4 = 10^7 Zufallszahlen, aber der zweite berechnet 10^2 * 10^3 * 10^4 = 10^9 Zufallszahlen, nein? – DSM

+0

@DSM: Whoops. Das falsche Ding zu der Zeit kopiert. Fixing ... – user2357112

1

Ich vermute, dass die Allgemeinheit von np.random.choice es verlangsamt sich, um so mehr für kleine Proben als große.

Ein rohes Vektorisierung der if Version ist:

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

in ipython Laufen bekomme ich:

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 

Also für die 1000 Größe, choice ist 3-4x langsamer, aber mit größeren Vektoren , der Unterschied beginnt zu verschwinden.