Número aleatório não repetitivo em numpy

88

Como posso gerar números aleatórios não repetitivos em numpy?

list = np.random.random_integers(20,size=(10))
Academia
fonte
O que você quer dizer com "não repetitivo"? Que a sequência de números aleatórios nunca se repete? Isso não é possível, uma vez que o estado do gerador de números aleatórios precisa caber na memória finita de um computador. Ou você quer dizer que nenhum número ocorre duas vezes?
Sven Marnach
5
Não repetitivo significa que você tem uma lista sem duplicatas.
Polinômio de
2
Talvez você precise de uma permutação aleatória? docs.scipy.org/doc/numpy/reference/generated/…
cyborg

Respostas:

106

numpy.random.Generator.choiceoferece um replaceargumento para provar sem substituição:

from numpy.random import default_rng

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

Se você estiver em um NumPy anterior ao 1.17, sem a GeneratorAPI, você pode usar a random.sample()partir da biblioteca padrão:

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

Você também pode usar numpy.random.shuffle()e fatiar, mas será menos eficiente:

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

Também há um replaceargumento na numpy.random.choicefunção de legado , mas esse argumento foi implementado de maneira ineficiente e, em seguida, deixado ineficiente devido às garantias de estabilidade do fluxo de número aleatório, portanto, seu uso não é recomendado. (Basicamente, ele faz o shuffle-and-slice internamente.)

Sven Marnach
fonte
1
print random.sample (range (20), 10) não funciona com python 2.6 ?!
Academia de
Você fez import random?
Sven Marnach
O problema era devido a uma configuração ruim do Pydev. Thks
Academia de
1
E se meu n não for 20, mas como 1000000, mas eu precisar de apenas 10 números exclusivos dele, existe uma abordagem mais eficiente de memória?
mrgloom
2
@mrgloom No Python 3, random.sample(range(n), 10))será eficiente mesmo para muito grandes n, já que um rangeobjeto é apenas um pequeno invólucro que armazena valores de início, parada e etapa, mas não cria a lista completa de inteiros. No Python 2, você pode substituir rangepor xrangepara obter um comportamento semelhante.
Sven Marnach,
107

Acho numpy.random.sampleque não funciona direito agora. Esta é a minha maneira:

import numpy as np
np.random.choice(range(20), 10, replace=False)
Strnam
fonte
25
Em vez de range(n)(ou arange(n)) como o primeiro argumento de choice, é equivalente a apenas passar n, por exemplo choice(20, 10, replace=False).
Josh Bode
1
Observe que np.random.choice(a, size, replace=False)é muito lento para grandes a- na minha máquina, cerca de 30 ms para a = 1M.
Matthew Rahtz
3
Para evitar problemas de tempo e memória para nuso muito grande numpy.random.Generator.choice(começando com numpy v1.17)
benbo
1
A principal desvantagem que vejo é np.random.choice não ter um parâmetro de eixo -> é apenas para matrizes 1d.
Moosefeather
3

Anos depois, algum tempo é necessário para escolher 40.000 de 10.000 ^ 2 (Numpy 1.8.1, imac 2.7 GHz):

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

(Por que escolher 40000 de 10000 ^ 2? Para gerar matrizes scipy.sparse.random grandes - scipy 1.4.1 usa np.random.choice( replace=False ), slooooow.)

Ponta do chapéu para pessoas numpy.random.

Denis
fonte
1

Você também pode conseguir isso classificando:

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

Simplesmente gere um array que contenha o intervalo de números necessário e embaralhe-os trocando repetidamente um aleatório pelo 0º elemento do array. Isso produz uma sequência aleatória que não contém valores duplicados.

Polinomial
fonte
2
Outra propriedade da sequência aleatória resultante é que ela não é particularmente aleatória .
Sven Marnach
@SvenMarnach - Para a maioria dos propósitos, porém, é aleatório o suficiente. Ele poderia usar a abordagem aleatória dupla se quisesse mais aleatória.
Polinômio de
Isso não tem sentido. O OP pode usar chamadas de biblioteca para fazer isso direito. Eles são mais fáceis de usar, funcionam mais rápido e são mais legíveis do que uma versão personalizada. Não consigo pensar em nenhuma razão para usar um algoritmo errado aqui, só porque é provavelmente "aleatório o suficiente", quando usar o algoritmo certo não tem nenhuma desvantagem.
Sven Marnach
@SvenMarnach - Bastante justo. Não sei entediante, então eu estava apenas oferecendo uma solução potencial.
Polinômio de