Получить среднее время выполнения из `%timeit` магии ipython

Попытка синхронизировать различные случайные функции, чтобы найти самый быстрый способ выбрать случайный элемент из списка. %timeit хочет дать мне «лучшее из 3» самое быстрое время, но поскольку прогоны случайны, время доступа сильно различается (захват из конца списка будет медленным; захват из начала будет быстрым).

Как мне получить среднее значение по всем циклам, а не лучшее из них?

a = [0,6,3,1,3,9,4,3,2,6]

%timeit random.choice(a)
%timeit a[random.randint(0,len(a)-1)]
%timeit a[np.random.randint(0,len(a)-1)]
%timeit np.random.choice(a,1)[0]

Текущий вывод (с учетом разницы во времени):

%timeit random.choice(a)
The slowest run took 9.87 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.23 µs per loop

Обновление: тупой подход:

%time for i in range(100000): random.choice(a)
%time for i in range(100000): a[random.randint(0,len(a)-1)]
%time for i in range(100000): a[np.random.randint(0,len(a)-1)]
%time for i in range(100000): np.random.choice(a,1)[0]

person nick_eu    schedule 12.02.2016    source источник
comment
Попытка синхронизировать различные случайные функции, чтобы найти самый быстрый способ выбрать случайный элемент из списка. -- Такая (вероятно) превентивная микрооптимизация ни к чему не приведет.   -  person kay    schedule 12.02.2016
comment
@Kay Я имитирую случайные блуждания в сети из десятков миллионов узлов. Обещаю, даже небольшие различия будут иметь большое значение. На данный момент случайные розыгрыши составляют 60% моего бегового времени. (И нет, это не упреждающее действие — я профилирую как сумасшедший)   -  person nick_eu    schedule 12.02.2016
comment
Вы пробовали рисовать из массива numpy, а не из списка? Я думаю, что np.random.choice приводит a к массиву, что может быть довольно дорого. Я вижу разницу в 6 раз для списка len(10) и массива.   -  person ali_m    schedule 12.02.2016
comment
Хм -- Не думаю, что я могу сделать это. У меня есть c-скомпилированная функция, дающая мне список в качестве входных данных в реальной программе, я только что создал список a в качестве примера. Но спасибо за мысль!   -  person nick_eu    schedule 13.02.2016


Ответы (2)


Вы можете использовать timeit.repeat:

import timeit
import numpy as np

reps = timeit.repeat(repeat=3, n=10000,
                     stmt="np.random.choice(a)",
                     setup="import numpy as np; a=[0,6,3,1,3,9,4,3,2,6]")

# taking the median might be better, since I suspect the distribution of times will
# be heavily skewed
avg = np.mean(reps)

Одна из потенциальных проблем заключается в том, что вы, вероятно, столкнетесь с эффектами кэширования, которые могут сделать ваши тайминги менее значимыми (см. здесь). Вы можете, например, захотеть создать новый случайный список на каждой итерации, используя аргумент setup=.

person ali_m    schedule 12.02.2016

Как быстро

random_fd = open('/dev/urandom', 'rb')

a = array.array('I')
a.read(random_fd, 10**8)

get_next_rand = iter(a).next

для тебя? Я бы просто сгенерировал огромное количество случайных чисел сразу, если это ваше узкое место.

На моем старом ПК:

%timeit array.array('I').read(open('/dev/urandom', 'rb'), 10**6)
1 loop, best of 3: 200 ms per loop
person kay    schedule 12.02.2016
comment
Это хорошая идея. Мне нужно будет настроить их позже — каждый список, из которого я выбираю, имеет разную длину, — но все же может быть более эффективным для генерации случайных чисел с плавающей запятой от 0 до 1, кратных по длине и округленных до целого числа. Спасибо! - person nick_eu; 13.02.2016
comment
Пожалуйста! Просто убедитесь, что вы не вводите смещение при использовании по модулю: stackoverflow.com/q/10984974/416224 - person kay; 13.02.2016