Ra

Random em Python

{one: "1 exercício", many: "%{count} de exercícios", other: "%{count} exercícios"}

Sobre Random

Muitos programas precisam de valores aleatórios (aparentemente) para simular eventos do mundo real.

Exemplos comuns e familiares incluem:

  • Um cara ou coroa: um valor aleatório de ('Heads', 'Tails').
  • O lançamento de um dado: um número inteiro aleatório de 1 a 6.
  • Embaralhar um baralho de cartas: uma ordenação aleatória de uma lista de cartas.

Gerar valores verdadeiramente aleatórios com um computador é um desafio técnico surpreendentemente difícil, então você pode ver esses resultados sendo chamados de "pseudoaleatórios".

Na prática, uma biblioteca bem projetada como o módulo random da biblioteca padrão do Python é rápida, flexível e produz resultados amplamente bons o suficiente para a maioria das aplicações em modelagem, simulação e jogos.

O restante desta página vai listar algumas das funções mais comuns em random. Recomendamos que você explore a documentação completa de random, pois há muito mais opções do que as que abordamos aqui.

Caution

O módulo random NÃO deve ser usado para aplicações de segurança ou criptográficas.

Em vez disso, o Python fornece o módulo secrets. Ele é especialmente otimizado para segurança criptográfica. Alguns dos problemas anteriores e dos motivos para criar o módulo secrets podem ser encontrados na PEP 506.

Importando

Antes de usar as ferramentas do módulo random, você precisa primeiro importá-lo:

>>> import random

# Choose random integer from a range
>>> random.randrange(1000)
360

>>> random.randrange(-1, 500)
228

>>> random.randrange(-10, 11, 2)
-8

# Choose random integer between two values (inclusive)
>>> random.randint(5, 25)
22

Para evitar digitar o nome do módulo, você pode importar funções específicas pelo nome:

>>> from random import choice, choices

# Using choice() to pick Heads or Tails 10 times
>>> tosses = []
... for side in range(10):
...    tosses.append(choice(['H', 'T']))    

>>> print(tosses)
['H', 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'H']


# Using choices() to pick Heads or Tails 8 times
>>> picks = []
... picks.extend(choices(['H', 'T'], k=8))
... print(picks)
['T', 'H', 'H', 'T', 'H', 'H', 'T', 'T']

Criando números inteiros aleatórios

A função randrange() tem três formas, para selecionar um valor aleatório de range(start, stop, step):

  1. randrange(stop) retorna um número inteiro n tal que 0 <= n < stop
  2. randrange(start, stop) retorna um número inteiro n tal que start <= n < stop
  3. randrange(start, stop, step) retorna um número inteiro n tal que start <= n < stop e n está na sequência start, start + step, start + 2*step...

Para o caso comum em que step == 1, a função randint(a, b) pode ser mais conveniente e legível. Os resultados possíveis de randint() incluem o limite superior, então randint(a, b) é o mesmo que usar randrange(a, b+1):

>>> import random

# Select one number at random from the range 0, 499
>>> random.randrange(500)
219

# Select 10 numbers at random between 0 and 9 two steps apart.
>>> numbers = []
... for integer in range(10):
...    numbers.append(random.randrange(0, 10, 2))

>>> print(numbers)
[2, 8, 4, 0, 4, 2, 6, 6, 8, 8]

# roll a die
>>> random.randint(1, 6)  
4

Trabalhando com sequências

As funções desta seção pressupõem que você está partindo de alguma sequência ou outro contêiner.

Normalmente será uma list ou, com algumas limitações, uma tuple ou um set (uma tuple é imutável e um set não tem ordem).

choice() e choices()

A função choice() retorna uma entrada escolhida aleatoriamente de uma determinada sequência. No caso mais simples, pode ser um cara ou coroa:

# This will pick one of the two values in the list at random 5 separate times 
>>> [random.choice(['H', 'T']) for _ in range(5)]
['T', 'H', 'H', 'T', 'H']

Poderíamos fazer essencialmente a mesma coisa usando a função choices(), fornecendo um argumento nomeado com o tamanho da lista:

>>> random.choices(['H', 'T'], k=5)
['T', 'H', 'T', 'H', 'H']

Nos exemplos acima, presumimos uma moeda honesta, com probabilidade igual de dar cara ou coroa, mas também é possível especificar pesos. Por exemplo, se um saco contém 10 bolas vermelhas e 15 bolas verdes, e queremos tirar uma aleatoriamente:

>>> random.choices(['red', 'green'], [10, 15])
['red']

sample()

O exemplo com choices() acima pressupõe o que os estatísticos chamam de "amostragem com reposição". Cada escolha não tem efeito sobre a probabilidade das escolhas futuras, e a distribuição das escolhas possíveis permanece a mesma de uma escolha para outra.

No exemplo com as bolas vermelhas e verdes: depois de cada escolha, devolvemos a bola ao saco e agitamos bem antes da próxima retirada. Isso contrasta com uma situação em que tiramos uma bola vermelha e ela fica de fora. Não devolver a bola significa que agora há menos bolas vermelhas no saco, e a próxima escolha tem agora menos chance de ser vermelha.

Para simular essa "amostragem sem reposição", o módulo random fornece a função sample(). A sintaxe de sample() é semelhante à de choices(), exceto que ela adiciona um parâmetro nomeado counts:

>>> random.sample(['red', 'green'], counts=[10, 15], k=10)
['green', 'green', 'green', 'green', 'green', 'red', 'red', 'red', 'red', 'green']

As amostras são retornadas na ordem em que foram escolhidas.

shuffle()

Tanto choices() quanto sample() retornam novas listas quando k > 1. Em contraste, shuffle() randomiza a ordem de uma lista no local, e a ordem original é perdida:

>>> my_list = [1, 2, 3, 4, 5]
>>> random.shuffle(my_list)
>>> my_list
[4, 1, 5, 2, 3]

Trabalhando com distribuições

Até agora, concentramo-nos nos casos em que todos os resultados têm a mesma probabilidade. Por exemplo, random.randrange(100) tem a mesma probabilidade de dar qualquer número inteiro de 0 a 99.

Muitas situações do mundo real são bem menos simples que isso. Como resultado, os estatísticos criaram uma grande variedade de distributions para descrever matematicamente resultados do "mundo real".

Distribuições uniformes

Para números inteiros, usam-se randrange() e randint() quando todas as probabilidades são iguais. Isso é chamado de distribuição uniform.

Existem equivalentes de ponto flutuante para randrange() e randint().

random() fornece um valor float x tal que 0.0 <= x < 1.0.

uniform(a, b) fornece x tal que a <= x <= b.

>>> [round(random.random(), 3) for _ in range(5)]
[0.876, 0.084, 0.483, 0.22, 0.863]

>>> [round(random.uniform(2, 5), 3) for _ in range(5)]
[2.798, 2.539, 3.779, 3.363, 4.33]

Distribuição gaussiana

Também chamada de distribuição "normal" ou curva "em forma de sino", é uma forma muito comum de descrever a imprecisão em valores medidos.

Por exemplo, suponha que a fábrica onde você trabalha acabou de comprar 10.000 parafusos que deveriam ser idênticos. Você quer configurar o robô da fábrica para lidar com eles, então pesa uma amostra de 100 e descobre que eles têm um peso médio (ou mean) de 4,731 g. É extremamente improvável que isso signifique que todos pesam exatamente 4,731 g. Talvez você descubra que os valores variam de 4,627 a 4,794 g, mas se concentram em torno de 4,731 g.

Essa é a Gaussian distribution, na qual as probabilidades atingem o pico na média e caem simetricamente dos dois lados (daí o "formato de sino"). Para simular isso em software, precisamos de alguma forma de especificar a largura da curva (tipicamente, parafusos caros se concentram mais em torno da média do que parafusos baratos!).

Por convenção, isso é feito com o standard deviation: valores pequenos para uma curva estreita e afiada, grandes para uma curva baixa e larga. Os matemáticos adoram letras gregas, então usamos μ ('mu') para representar a média e σ ('sigma') para representar o desvio padrão. Assim, se você ler que "95% dos valores estão dentro de 2σ de μ" ou que "o bóson de Higgs foi detectado com confiança de 5 sigma", esses comentários se referem ao desvio padrão.

>>> mu = 4.731
>>> sigma = 0.316
>>> [round(random.gauss(mu, sigma), 3) for _ in range(5)]
[4.72, 4.957, 4.64, 4.556, 4.968]
Editar via GitHub O link abre em uma nova janela ou aba