Diferenças entre numpy.random e random.random em Python

100

Eu tenho um grande script em Python. Eu me inspirei no código de outras pessoas, então acabei usando o numpy.randommódulo para algumas coisas (por exemplo, para criar um array de números aleatórios retirados de uma distribuição binomial) e em outros lugares eu uso o módulo random.random.

Alguém pode me dizer as principais diferenças entre os dois? Olhando para a página da web do doc para cada um dos dois, parece-me que numpy.randomapenas tem mais métodos, mas não estou certo sobre como a geração dos números aleatórios é diferente.

A razão pela qual estou perguntando é porque preciso propagar meu programa principal para fins de depuração. Mas não funciona a menos que eu use o mesmo gerador de números aleatórios em todos os módulos que estou importando, correto?

Além disso, li aqui, em outro post, uma discussão sobre NÃO usar numpy.random.seed(), mas não entendi direito por que isso era uma ideia tão ruim. Eu realmente apreciaria se alguém me explicasse por que isso acontece.

Laura
fonte

Respostas:

120

Você já fez muitas observações corretas!

A menos que você queira semear os dois geradores aleatórios, provavelmente é mais simples no longo prazo escolher um ou outro. Mas se você precisar usar ambos, então sim, você também precisará semear os dois, porque eles geram números aleatórios independentemente um do outro.

Pois numpy.random.seed(), a principal dificuldade é que não é seguro para thread - isto é, não é seguro usar se você tiver muitos threads diferentes de execução , porque não é garantido que funcione se duas threads diferentes estiverem executando a função ao mesmo tempo. Se você não estiver usando threads, e se puder razoavelmente esperar que não precise reescrever seu programa dessa maneira no futuro, tudo numpy.random.seed()bem. Se houver alguma razão para suspeitar que você possa precisar de threads no futuro, é muito mais seguro a longo prazo fazer conforme sugerido e criar uma instância local da numpy.random.Randomclasse . Pelo que eu posso dizer, random.random.seed()é thread-safe (ou pelo menos, não encontrei nenhuma evidência do contrário).

A numpy.randombiblioteca contém algumas distribuições de probabilidade extras comumente usadas em pesquisas científicas, bem como algumas funções de conveniência para gerar matrizes de dados aleatórios. A random.randombiblioteca é um pouco mais leve e deve funcionar se você não estiver fazendo pesquisas científicas ou outros tipos de trabalho em estatística.

Caso contrário, ambos usam a sequência de torção de Mersenne para gerar seus números aleatórios e são completamente determinísticos - ou seja, se você souber algumas informações importantes, é possível prever com certeza absoluta qual número virá a seguir . Por esse motivo, nem numpy.random nem random.random é adequado para qualquer uso criptográfico sério . Mas, como a sequência é muito longa, ambos são adequados para gerar números aleatórios nos casos em que você não está preocupado com as pessoas tentando fazer a engenharia reversa de seus dados. Esta também é a razão para a necessidade de semear o valor aleatório - se você começar no mesmo lugar todas as vezes, sempre obterá a mesma sequência de números aleatórios!

Como uma nota lateral, se você não precisa aleatoriedade nível de criptografia, você deve usar a segredos módulo, ou algo parecido Crypto.Random se você estiver usando uma versão do Python mais cedo do que Python 3.6.

Hannele
fonte
14
Como uma observação remotamente relacionada, às vezes é necessário usar nenhum dos dois , já que o twister de Mersenne não produz sequências aleatórias de entropia suficientes para fins criptográficos (e alguns científicos incomuns). Nesses casos raros, você geralmente precisa do Crypto.Random , que é capaz de usar fontes de entropia específicas do sistema operacional para gerar sequências aleatórias não determinísticas de qualidade muito mais alta do que está disponível random.randomsozinho. Você geralmente não precisa disso, no entanto.
SingleNegationElimination
Obrigado Hannnele. Seus insights foram realmente muito úteis! Acontece que não consigo usar APENAS um único gerador de números aleatórios (que precisa ser numpy, já que aleatório não produz distribuições binomiais) porque partes do meu programa chamam outro programa que usa aleatório. Terei que semear os dois geradores.
Laura
2
"se você sabe qual número você tem agora, é possível prever com certeza absoluta qual será o próximo número." Acho que esta declaração pode precisar de alguns esclarecimentos. O que se quer dizer é que, se você souber o estado interno do gerador, poderá reproduzir a sequência - que é o que você faz quando semeia o gerador. Dada a saída de um único número do gerador, você não pode prever o próximo número. O período é tão grande que você provavelmente precisaria de uma longa sequência de números antes de poder calcular onde está na sequência pseudo-aleatória e, assim, prever a próxima.
Kaushik Ghose
12

Do Python for Data Analysis , o módulo numpy.randomcomplementa o Python randomcom funções para gerar matrizes inteiras de valores de amostra de vários tipos de distribuição de probabilidade de maneira eficiente.

Por outro lado, o randommódulo integrado do Python mostra apenas um valor por vez, enquanto numpy.randompode gerar uma amostra muito grande mais rápido. Usando a função mágica do IPython, %timeité possível ver qual módulo tem desempenho mais rápido:

In [1]: from random import normalvariate
In [2]: N = 1000000

In [3]: %timeit samples = [normalvariate(0, 1) for _ in xrange(N)]
1 loop, best of 3: 963 ms per loop

In [4]: %timeit np.random.normal(size=N)
10 loops, best of 3: 38.5 ms per loop
lmiguelvargasf
fonte
1
Não é o caso de outros métodos. em comparação np.random.randint(2)com random.randrange(2)e NumPy era mais lento . NumPy: 1,25 us e Random: 891 ns. E também a mesma relação para np.random.rand()e random.random().
Shayan Amani
3

A fonte da semente e o perfil de distribuição usado afetarão as saídas - se você estiver procurando por aleatoriedade criptográfica, a propagação de os.urandom () obterá bytes aleatórios quase reais da vibração do dispositivo (ou seja, ethernet ou disco) (ou seja / dev / random no BSD)

isso evitará que você forneça uma semente e, assim, gere números aleatórios determinísticos. No entanto, as chamadas aleatórias permitem que você ajuste os números a uma distribuição (o que eu chamo de aleatoriedade científica - eventualmente, tudo o que você quer é uma distribuição em curva de sino de números aleatórios, numpy é o melhor em fornecer isso.

ASSIM, sim, fique com um gerador, mas decida o que você quer aleatório - aleatório, mas definitivamente a partir de uma curva de distribuição, ou tão aleatório quanto você pode obter sem um dispositivo quântico.

seu canalha senhor - pegue isso
fonte
Muito obrigado Paul, sua resposta foi muito útil! Não estou procurando aleatoriedade criptográfica, estou fazendo modelagem matemática e números pseudo-aleatórios são suficientes para mim. Acontece que não posso me limitar a um gerador como queria, pois preciso do numpy para a distribuição binomial e meu programa chama outro programa que usa aleatório :(
Laura