Неповторюване випадкове число в numpy


88

Як я можу генерувати неповторювані випадкові числа в numpy?

list = np.random.random_integers(20,size=(10))

Що ви маєте на увазі під "неповторюваним"? Що послідовність випадкових чисел ніколи не повторюється? Це неможливо, оскільки стан генератора випадкових чисел повинен поміститися в кінцевій пам’яті комп’ютера. Або ви маєте на увазі, що жодне окреме число не трапляється двічі?
Sven Marnach

5
Неповторюване означає, що у вас є список без дублікатів.
Поліном

2
Можливо, вам потрібна випадкова перестановка? docs.scipy.org/doc/numpy/reference/generated/…
кіборг

Відповіді:


106

numpy.random.Generator.choiceпропонує replaceаргумент для вибірки без заміни:

from numpy.random import default_rng

rng = default_rng()
numbers = rng.choice(20, size=10, replace=False)

Якщо ви використовуєте NumPy до 1.17, без GeneratorAPI, ви можете використовувати random.sample()зі стандартної бібліотеки:

print(random.sample(range(20), 10))

Ви також можете використовувати numpy.random.shuffle()і нарізку, але це буде менш ефективно:

a = numpy.arange(20)
numpy.random.shuffle(a)
print a[:10]

У replaceзастарілій numpy.random.choiceфункції також є аргумент , але цей аргумент був реалізований неефективно, а потім залишився неефективним через гарантії стабільності потоку випадкових чисел, тому його використання не рекомендується. (Це в основному робить перемішування та нарізку всередині.)


1
друкувати random.sample (діапазон (20), 10) не працює з python 2.6 ?!
Академія

Ти що import random?
Sven Marnach

Проблема була пов’язана з поганою конфігурацією Pydev. Thks
Academia

1
Що робити, якщо мій n не 20, а подобається 1000000, але мені потрібно лише 10 унікальних чисел з нього, чи є більш ефективний підхід до пам'яті?
mrgloom

2
@mrgloom У Python 3 random.sample(range(n), 10))буде ефективним навіть для дуже великих n, оскільки rangeоб'єкт - це лише невелика обгортка, що зберігає значення start, stop і step, але не створює повного списку цілих чисел. У Python 2 ви можете замінити rangeна, xrangeщоб отримати подібну поведінку.
Sven Marnach

108

Думаю, зараз numpy.random.sampleце не працює правильно. Це мій шлях:

import numpy as np
np.random.choice(range(20), 10, replace=False)

25
Замість range(n)(або arange(n)) як першого аргументу choice, це еквівалентно просто передачі n, наприклад choice(20, 10, replace=False).
Джош Боде

1
Зверніть увагу, що np.random.choice(a, size, replace=False)для великих це дуже повільно a- на моїй машині близько 30 мс для a = 1M.
Matthew Rahtz

3
Щоб уникнути проблем із часом та пам'яттю для дуже великого nвикористання numpy.random.Generator.choice(починаючи з numpy v1.17)
benbo

1
Основним недоліком, який я бачу, є np.random.choice не має параметра осі -> це лише для 1d масивів.
Moosefeather

3

Через кілька років, через деякий час, він обрав 40000 з 10000 ^ 2 (Numpy 1.8.1, imac 2,7 ГГц):

import random
import numpy as np

n = 10000
k = 4
np.random.seed( 0 )

%timeit np.random.choice( n**2, k * n, replace=True )  # 536 µs ± 1.58 µs
%timeit np.random.choice( n**2, k * n, replace=False ) # 6.1 s ± 9.91 ms

# https://docs.scipy.org/doc/numpy/reference/random/index.html
randomstate = np.random.default_rng( 0 )
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=False )  # 766 µs ± 2.18 µs
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=True )   # 1.05 ms ± 1.41 µs

%timeit random.sample( range( n**2 ), k * n )          # 47.3 ms ± 134 µs

(Чому вибрати 40000 з 10000 ^ 2? Для створення великих матриць scipy.sparse.random - використовує scipy 1.4.1 np.random.choice( replace=False ), slooooow.)

Підказка капелюха numpy. випадкових людей.


1

Ви можете отримати це, також сортуючи:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)

-3

Просто згенеруйте масив, що містить необхідний діапазон чисел, а потім перемішайте їх, повторно обміняючи випадковий номер 0-м елементом масиву. Це створює випадкову послідовність, яка не містить повторюваних значень.


2
Інша властивість результуючої випадкової послідовності полягає в тому, що вона не є особливо випадковою .
Sven Marnach

@SvenMarnach - однак для більшості цілей це досить випадково. Він міг застосувати подвійний випадковий підхід, якщо хотів, щоб він був більш випадковим.
Поліном

Це безглуздо. OP може використовувати дзвінки з бібліотеки, щоб зробити це правильно. Вони простіші у використанні, працюють швидше та читабельніші, ніж власна версія. Я не можу придумати жодної причини, чому я мав би використовувати неправильний алгоритм тут, лише тому, що він, мабуть, "досить випадковий", коли використання правильного алгоритму не має жодних недоліків.
Sven Marnach

@SvenMarnach - Досить справедливо. Я не знаю numpy, тому я просто пропонував потенційне рішення.
Поліном
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.