Эффективное создание нескольких экземпляров numpy.random.choice без замены

Я новичок в Python. При чтении, пожалуйста, укажите любые другие предложения относительно способов улучшения моего кода на Python.

Вопрос: Как создать массив размером 8xN в Python, содержащий случайные числа? Ограничение состоит в том, что каждый столбец этого массива должен содержать 8 ничьих без замены целочисленного набора [1,8] . Точнее, когда N = 10, я хочу что-то вроде этого.

[[ 6. 2. 3. 4. 7. 5. 5. 7. 8. 4.] [ 1. 4. 5. 5. 4. 4. 8. 5. 7. 5.] [ 7. 3. 8. 8. 3. 8. 7. 3. 6. 7.] [ 3. 6. 7. 1. 5. 6. 2. 1. 5. 1.] [ 8. 1. 4. 3. 8. 2. 3. 4. 3. 3.] [ 5. 8. 1. 7. 1. 3. 6. 8. 1. 6.] [ 4. 5. 2. 6. 2. 1. 1. 6. 4. 2.] [ 2. 7. 6. 2. 6. 7. 4. 2. 2. 8.]] 

Для этого я использую следующий подход:

 import numpy.random import numpy def rand_M(N): M = numpy.zeros(shape = (8, N)) for i in range (0, N): M[:, i] = numpy.random.choice(8, size = 8, replace = False) + 1 return M 

На практике N будет ~ 1e7. Алгоритм, описанный выше, равен O (n) по времени и занимает приблизительно 0,38 секунды при N = 1e3. Поэтому время, когда N = 1e7 составляет ~ 1 ч (т. Е. 3800 секунд). Должен быть гораздо более эффективный способ.

Сроки выполнения функции

 from timeit import Timer t = Timer(lambda: rand_M(1000)) print(t.timeit(5)) 0.3863314103162543 

4 Solutions collect form web for “Эффективное создание нескольких экземпляров numpy.random.choice без замены”

Создайте случайный массив указанной формы, а затем отсортируйте вдоль оси, где вы хотите сохранить лимиты, что дает нам векторизованное и очень эффективное решение. Это будет основано на этом smart answer на MATLAB randomly permuting columns differently . Вот реализация –

Пример прогона –

 In [122]: N = 10 In [123]: np.argsort(np.random.rand(8,N),axis=0)+1 Out[123]: array([[7, 3, 5, 1, 1, 5, 2, 4, 1, 4], [8, 4, 3, 2, 2, 8, 5, 5, 6, 2], [1, 2, 4, 6, 5, 4, 4, 3, 4, 7], [5, 6, 2, 5, 8, 2, 7, 8, 5, 8], [2, 8, 6, 3, 4, 7, 1, 1, 2, 6], [6, 7, 7, 8, 6, 6, 3, 2, 7, 3], [4, 1, 1, 4, 3, 3, 8, 6, 8, 1], [3, 5, 8, 7, 7, 1, 6, 7, 3, 5]], dtype=int64) 

Тесты времени выполнения –

 In [124]: def sortbased_rand8(N): ...: return np.argsort(np.random.rand(8,N),axis=0)+1 ...: ...: def rand_M(N): ...: M = np.zeros(shape = (8, N)) ...: for i in range (0, N): ...: M[:, i] = np.random.choice(8, size = 8, replace = False) + 1 ...: return M ...: In [125]: N = 5000 In [126]: %timeit sortbased_rand8(N) 100 loops, best of 3: 1.95 ms per loop In [127]: %timeit rand_M(N) 1 loops, best of 3: 233 ms per loop 

Таким образом, 120x 120- 120x ускорение!

Как насчет перетасовки, то есть перестановки?

 import random import numpy from timeit import Timer def B_rand_M(N): a = numpy.arange(1,9) M = numpy.zeros(shape = (8, N)) for i in range (0, N): M[:, i] = numpy.random.permutation(a) return M # your original implementation def J_rand_M(N): M = numpy.zeros(shape = (8, N)) for i in range (0, N): M[:, i] = numpy.random.choice(8, size = 8, replace = False) + 1 return M 

некоторые тайминги:

 def compare(N): for f in (J_rand_M, B_rand_M): t = Timer(lambda: f(N)).timeit(6) print 'time for %s(%s): %.6f' % (f.__name__, N, t) for i in range(6): print 'N = 10^%s' % i compare(10**i) print 

дает

 N = 10^0 time for J_rand_M(1): 0.001199 time for B_rand_M(1): 0.000080 N = 10^1 time for J_rand_M(10): 0.001112 time for B_rand_M(10): 0.000335 N = 10^2 time for J_rand_M(100): 0.011118 time for B_rand_M(100): 0.003022 N = 10^3 time for J_rand_M(1000): 0.110887 time for B_rand_M(1000): 0.030528 N = 10^4 time for J_rand_M(10000): 1.100540 time for B_rand_M(10000): 0.304696 N = 10^5 time for J_rand_M(100000): 11.151576 time for B_rand_M(100000): 3.049474 

Просто комментируйте ваш анализ во время выполнения проблемы – моя интуиция заключается в том, что O (n) – это наилучшее возможное время выполнения, которое вы можете получить при генерации случайных чисел O (n).

Вы пробовали на самом деле управлять своим кодом с n = 10 миллионов? Ваше предположение о том, что время выполнения будет масштабироваться на 1000 при возрастании входных данных в 1000 раз, может быть неверным на практике, так как обычно существует постоянный термин при выполнении любой программы (загрузки библиотек и т. Д.), Что может быть значительным в зависимости от проблема.

Это, как говорится, похоже, что вопрос, связанный с Эриком Райт, выполняет очень тщательную работу и может легко адаптироваться под ваш вопрос.

Используйте приведенный ниже код для генерации массива

 import numpy as np N=1e7 # THe value you want to have np.random.randint(1,high=8,size=(8,N)) 

Надеюсь, что это поможет, это, безусловно, не займет много времени.

  • Структурированный массив Python Numpy (recarray), назначающий значения в срезы
  • Как изменить оси matplotlib так, чтобы это не отображалось в научной нотации?
  • Проблемы с компилятором с помощью pip во время установки numpy в Windows 8.1, 7 Enterprise и 7 Home Editions
  • Сделка с переполнением в exp с использованием numpy
  • Почему `numpy.einsum` работает быстрее с` float32`, чем `float16` или` uint16`?
  • Изменение форм данных в пандах на основе меток столбцов
  • Почему Numpy.all () и any () дают неправильные результаты, если вы используете выражения генератора?
  • Создание pyplot.hist () первого и последнего бункеров включает выбросы
  • Python - лучший язык программирования в мире.