9.6. random — Gera números pseudoaleatórios

Código Fonte: Lib/random.py


Este módulo implementa geradores de números pseudoaleatórios para várias distribuições.

Para números inteiros, há uma seleção uniforme de um intervalo. Para sequências, há uma seleção uniforme de um elemento aleatório, uma função para gerar uma permutação aleatória de uma lista no local e uma função para amostragem aleatória sem substituição.

Na linha real, existem funções para calcular distribuições uniforme, normal (gaussiana), lognormal, exponencial negativa, gama e beta. Para gerar distribuições de ângulos, a distribuição de von Mises está disponível.

Quase todas as funções do módulo dependem da função básica random(), que gera um ponto flutuante aleatório uniformemente no intervalo semiaberto [0.0, 1.0). O Python usa o Mersenne Twister como gerador de núcleo. Produz pontos flutuantes de precisão de 53 bits e possui um período de 2**19937-1. A implementação subjacente em C é rápida e segura para threads. O Mersenne Twister é um dos geradores de números aleatórios mais amplamente testados existentes. No entanto, sendo completamente determinístico, não é adequado para todos os fins e é totalmente inadequado para fins criptográficos.

As funções fornecidas por este módulo são, na verdade, métodos vinculados de uma instância oculta da classe random.Random. Você pode instanciar suas próprias instâncias de Random para obter geradores que não compartilham estado.

A classe Random também pode ser usado como subclasse se você quiser usar um gerador básico diferente de sua preferência: nesse caso, substitua os métodos random(), seed(), getstate() e setstate(). Opcionalmente, um novo gerador pode fornecer um método getrandbits() — isso permite que randrange() produza seleções a um intervalo grande arbitrário.

O módulo random também fornece a classe SystemRandom que usa a função do sistema os.urandom() para gerar números aleatórios a partir de fontes fornecidas pelo sistema operacional.

Aviso

The pseudo-random generators of this module should not be used for security purposes.

Bookkeeping functions:

random.seed(a=None, version=2)

Inicializa o gerador de números aleatórios.

Se a for omitido ou None, a hora atual do sistema será usada. Se fontes de aleatoriedade são fornecidas pelo sistema operacional, elas são usadas no lugar da hora do sistema (consulte a função os.urandom() para detalhes sobre disponibilidade).

Se a é um int, ele é usado diretamente.

Com a versão 2 (o padrão), o objeto a str, bytes ou bytearray é convertido em um objeto int e todos os seus bits são usados.

Com a versão 1 (fornecida para reproduzir sequências aleatórias de versões mais antigas do Python), o algoritmo para str e bytes gera um intervalo mais restrito de sementes.

Alterado na versão 3.2: Movido para o esquema da versão 2, que usa todos os bits em uma semente de strings.

random.getstate()

Retorna um objeto capturando o estado interno atual do gerador. Este objeto pode ser passado para setstate() para restaurar o estado.

random.setstate(state)

state deveria ter sido obtido de uma chamada anterior para getstate(), e setstate() restaura o estado interno do gerador para o que era no momento getstate() foi chamado.

random.getrandbits(k)

Retorna um número inteiro Python com bits aleatórios k. Este método é fornecido com o gerador MersenneTwister e alguns outros geradores também podem fornecê-lo como uma parte opcional da API. Quando disponível, getrandbits() permite que randrange() manipule intervalos arbitrariamente grandes.

Functions for integers:

random.randrange(stop)
random.randrange(start, stop[, step])

Retorna um elemento selecionado aleatoriamente em range(start, stop, step). Isso é equivalente a choice(range(start, stop, step)), mas na verdade não cria um objeto range.

O padrão de argumento posicional corresponde ao de range(). Os argumentos nomeados não devem ser usados porque a função pode usá-los de maneiras inesperadas.

Alterado na versão 3.2: randrange() é mais sofisticado em produzir valores igualmente distribuídos. Anteriormente, usava um estilo como int(random()*n), que poderia produzir distribuições ligeiramente desiguais.

random.randint(a, b)

Retorna um inteiro aleatório N de forma que a <= N <= b. Apelido para randrange(a, b+1).

Functions for sequences:

random.choice(seq)

Retorna um elemento aleatório da sequência não vazia seq. Se seq estiver vazio, levanta IndexError.

random.shuffle(x[, random])

Shuffle the sequence x in place. The optional argument random is a 0-argument function returning a random float in [0.0, 1.0); by default, this is the function random().

Note that for even rather small len(x), the total number of permutations of x is larger than the period of most random number generators; this implies that most permutations of a long sequence can never be generated.

random.sample(population, k)

Retorna uma lista de comprimento k de elementos exclusivos escolhidos a partir da sequência ou conjunto da população. Usado para amostragem aleatória sem substituição.

Retorna uma nova lista contendo elementos da população, mantendo a população original inalterada. A lista resultante está na ordem de seleção, para que todas as sub-fatias também sejam amostras aleatórias válidas. Isso permite que os vencedores do sorteio (a amostra) sejam divididos em grandes prêmios e vencedores de segundo lugar (as sub-fatias).

Os membros da população não precisam ser hasheáveis ou único. Se a população contiver repetições, cada ocorrência é uma seleção possível na amostra.

To choose a sample from a range of integers, use an range() object as an argument. This is especially fast and space efficient for sampling from a large population: sample(range(10000000), 60).

Se o tamanho da amostra for maior que o tamanho da população, uma ValueError é levantada.

As funções a seguir geram distribuições específicas com valor real. Os parâmetros de função são nomeados após as variáveis correspondentes na equação da distribuição, conforme usadas na prática matemática comum; a maioria dessas equações pode ser encontrada em qualquer texto estatístico.

random.random()

Retorna o próximo número de ponto flutuante aleatório no intervalo [0.0, 1.0).

random.uniform(a, b)

Retorna um número de ponto flutuante aleatório N de forma que a <= N <= b para a <= b e b <= N <= a para b < a.

O valor do ponto final b pode ou não ser incluído no intervalo, dependendo do arredondamento do ponto flutuante na equação a + (b-a) * random().

random.triangular(low, high, mode)

Retorna um número de ponto flutuante aleatório N de forma que low <= N <= high e com o modo mode especificado entre esses limites. Os limites low e high são padronizados como zero e um. O argumento mode assume como padrão o ponto médio entre os limites, fornecendo uma distribuição simétrica.

random.betavariate(alpha, beta)

Distribuição beta. As condições nos parâmetros são alpha > 0 e beta > 0. Os valores retornados variam entre 0 e 1.

random.expovariate(lambd)

Distribuição exponencial. lambd é 1.0 dividido pela média desejada. Deve ser diferente de zero. (O parâmetro seria chamado “lambda”, mas é uma palavra reservada em Python.) Os valores retornados variam de 0 a infinito positivo se lambd for positivo e de infinito negativo a 0 se lambd for negativo.

random.gammavariate(alpha, beta)

Distribuição gama. (Não a função gama!) As condições nos parâmetros são alpha > 0 e beta > 0.

A função de distribuição de probabilidade é:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha
random.gauss(mu, sigma)

Distribuição gaussiana. mu é a média e sigma é o desvio padrão. Isso é um pouco mais rápido que a função normalvariate() definida abaixo.

random.lognormvariate(mu, sigma)

Distribuição log normal. Se você usar o logaritmo natural dessa distribuição, obterá uma distribuição normal com média mu e desvio padrão sigma. mu pode ter qualquer valor e sigma deve ser maior que zero.

random.normalvariate(mu, sigma)

Distribuição normal. mu é a média e sigma é o desvio padrão.

random.vonmisesvariate(mu, kappa)

mu é o ângulo médio, expresso em radianos entre 0 e 2*pi, e kappa é o parâmetro de concentração, que deve ser maior ou igual a zero. Se kappa for igual a zero, essa distribuição será reduzida para um ângulo aleatório uniforme no intervalo de 0 a 2*pi.

random.paretovariate(alpha)

Distribuição de Pareto. alpha é o parâmetro de forma.

random.weibullvariate(alpha, beta)

Distribuição Weibull. alpha é o parâmetro de escala e beta é o parâmetro de forma.

Alternative Generator:

class random.SystemRandom([seed])

Classe que usa a função os.urandom() para gerar números aleatórios a partir de fontes fornecidas pelo sistema operacional. Não disponível em todos os sistemas. Não depende do estado do software e as sequências não são reproduzíveis. Assim, o método seed() não tem efeito e é ignorado. Os métodos getstate() e setstate() levantam NotImplementedError se chamados.

Ver também

M. Matsumoto and T. Nishimura, “Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator”, ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.3–30 1998.

Receita de Complementary-Multiply-with-Carry para um gerador de números aleatórios alternativo compatível com um longo período e operações de atualização comparativamente simples.

9.6.1. Notas sobre reprodutibilidade

Sometimes it is useful to be able to reproduce the sequences given by a pseudo random number generator. By re-using a seed value, the same sequence should be reproducible from run to run as long as multiple threads are not running.

A maioria dos algoritmos e funções de propagação do módulo aleatório está sujeita a alterações nas versões do Python, mas dois aspectos são garantidos para não serem alterados:

  • Se um novo método de semeadura for adicionado, será oferecida uma semeadora compatível com versões anteriores.
  • O método do gerador random() continuará produzindo a mesma sequência quando o semeador compatível receber a mesma semente.

9.6.2. Exemplos e receitas

Basic usage:

>>> random.random()                      # Random float x, 0.0 <= x < 1.0
0.37444887175646646

>>> random.uniform(1, 10)                # Random float x, 1.0 <= x < 10.0
1.1800146073117523

>>> random.randrange(10)                 # Integer from 0 to 9
7

>>> random.randrange(0, 101, 2)          # Even integer from 0 to 100
26

>>> random.choice('abcdefghij')          # Single random element
'c'

>>> items = [1, 2, 3, 4, 5, 6, 7]
>>> random.shuffle(items)
>>> items
[7, 3, 2, 5, 6, 4, 1]

>>> random.sample([1, 2, 3, 4, 5],  3)   # Three samples without replacement
[4, 1, 5]

A common task is to make a random.choice() with weighted probabilities.

If the weights are small integer ratios, a simple technique is to build a sample population with repeats:

>>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)]
>>> population = [val for val, cnt in weighted_choices for i in range(cnt)]
>>> population
['Red', 'Red', 'Red', 'Blue', 'Blue', 'Yellow', 'Green', 'Green', 'Green', 'Green']

>>> random.choice(population)
'Green'

A more general approach is to arrange the weights in a cumulative distribution with itertools.accumulate(), and then locate the random value with bisect.bisect():

>>> choices, weights = zip(*weighted_choices)
>>> cumdist = list(itertools.accumulate(weights))
>>> cumdist            # [3, 3+2, 3+2+1, 3+2+1+4]
[3, 5, 6, 10]

>>> x = random.random() * cumdist[-1]
>>> choices[bisect.bisect(cumdist, x)]
'Blue'