2013-09-04 3 views
6

При написании сценария я обнаружил функцию numpy.random.choice. Я реализовал его, потому что он был намного чище, чем эквивалентный оператор if. Однако после запуска скрипта я понял, что значительно медленнее, чем оператор if.Почему random.choice так медленно?

Ниже приведено MWE. Первый метод принимает 0,0 с, а второй - 7,2 с. Если вы масштабируете цикл i, вы увидите, как быстро random.choice замедляется.

Может ли кто-нибудь прокомментировать, почему random.choice настолько медленнее?

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

Это не очень хорошее сравнение. Каждый раз numpy должен принимать кумулятивную сумму p-списка, помещать его в новый вектор и затем перебирать по нему. Вы эффективно выполняете предварительную обработку, зная, что есть только три переменные и что сумма первого и третьего равна .5. Помимо этого, как отмечено ниже, numpy оптимизирован для векторизованных операций, а не для выполнения одной простой операции тысячи раз. –

+1

Кроме того, используйте 'timeit', а не' time' самостоятельно. – Marcin

ответ

12

Вы используете его неправильно. Vectorize операции или NumPy не будет предлагать никакой пользы:

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

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 Это примерно в 7 раз быстрее, чем первый цикл. –

+0

Как написано, вы сравниваете яблоки с яблоками? Первый вычисляет 10^3 * 10^4 = 10^7 случайных чисел, но второй вычисляет 10^2 * 10^3 * 10^4 = 10^9 случайных чисел, нет? – DSM

+0

@ DSM: Упс. Скопировано неточно. Фиксация ... – user2357112

1

Я подозреваю, что общность np.random.choice замедляет его вниз, тем более для малых выборок, чем крупные.

Сырых векторизации версии if является:

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

Запуска в ipython я получаю:

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 

Так что для 1000 размера, choice является 3-4x медленнее, но с большими векторами , разница начинает исчезать.

Смежные вопросы