Python3标准库:random伪随机数⽣成器
1. random伪随机数⽣成器
random模块基于Mersenne Twister算法提供了⼀个快速伪随机数⽣成器。原来开发这个⽣成器是为了向蒙特卡洛模拟⽣成输⼊,Mersenne Twister算法会⽣成⼤周期近均匀分布的数,因此适⽤于⼤量不同类型的应⽤。
1.1 ⽣成随机数
random()函数从所⽣成的序列返回下⼀个随机的浮点值。返回的所有值都落在0<=n<1.0区间内。
import random
for i in range(5):
print('%04.3f' % random.random(), end='')
print()
重复运⾏这个程序会产⽣不同的数字序列。
要⽣成⼀个指定数值区间内的数,则要使⽤uniform()。
import random
for i in range(5):
print('{:04.3f}'.format(random.uniform(1, 100)), end='')
print()
传⼊最⼩值和最⼤值,uniform()会使⽤公式min+(max-min)*random()来调整random()的返回值。
1.2 指定种⼦
每次调⽤random()都会⽣成不同的值,并且在⼀个⾮常⼤的周期之后数字才会重复。这对于⽣成唯⼀值或变化的值很有⽤,不过有些情况下可能需要提供相同的数据集,从⽽以不同的⽅式处理。对此,⼀种技术是使⽤⼀个程序⽣成随机值,并保存这些随机值,以便在另⼀个步骤中再做处理。不过,这对于量很⼤的数据来说可能并不实⽤,所以random包含了⼀个seed()函数,可以⽤来初始化伪随机数⽣成器,使它能⽣成⼀个期望的值集。
import random
random.seed(1)
for i in range(5):
print('{:04.3f}'.format(random.random()), end='')
print()
种⼦(seed)值会控制由公式⽣成的第⼀个值,该公式可⽤来⽣成伪随机数。由于公式是确定的,所以改变种⼦后便设置了将⽣成的整个序列。seed()的参数可⽤是任意的可散列对象。默认为使⽤⼀个平台特定的随机源(如果有的话)。但如果没有这样⼀个随机源,则使⽤当前时间。
1.3 保存状态
random()使⽤的伪随机算法的内部状态可以保存,并⽤于控制后续⽣成的随机数。如果在继续⽣成随机数之前恢复前⼀个状态,则会减少出现重复的可能性,即避免出现之前输⼊中重复的值或值序列。getstate()函数会返回⼀些数据,以后可以借助setstate()利⽤这些数据重新初始化伪随机数⽣成器。
import random
import os
import pickle
if ists('state.dat'):
# Restore the previously saved state
print('Found state.dat, initializing random module')
with open('state.dat', 'rb') as f:
state = pickle.load(f)
random.setstate(state)
else:
# Use a well-known start state
print('No state.dat, seeding')
random.seed(1)
# Produce random values
for i in range(3):
print('{:04.3f}'.format(random.random()), end='')
print()
# Save state for next time
with open('state.dat', 'wb') as f:
pickle.state(), f)
# Produce more random values
print('\nAfter saving state:')
for i in range(3):
print('{:04.3f}'.format(random.random()), end='')
print()
getstate()返回的数据是⼀个实现细节,所以这个例⼦⽤pickle将数据保存到⼀个⽂件;否则,它会把伪随机数⽣成器当作⼀个⿊盒。如果程序开始时这个⽂件存在,则加载原来的状态并继续。每次运⾏时都会在保存状态之前和之后⽣成⼀些数,以展⽰恢复状态会使⽣成器再次⽣
第⼀次:
第⼆次:
1.4 随机整数
random()将⽣成浮点数。可以把结果转换为整数,不过直接使⽤randint()⽣成整数会更⽅便。
import random
print('[1, 100]:', end='')
for i in range(3):
print(random.randint(1, 100), end='')
print('\n[-5, 5]:', end='')
for i in range(3):
print(random.randint(-5, 5), end='')
print()
randint()的参数是值的闭区间的两端。这些数可以是正数或负数,不过第⼀个值要⼩于第⼆个值。
randrange()是从区间选择值的⼀种更⼀般的形式。
import random
for i in range(3):
print(random.randrange(0, 101, 5), end='')
print()
除了开始值(start)和结束值(stop),randrange()还⽀持⼀个步长(step)参数,所以它完全等价于从range(start,stop,step)选择⼀个随机值。不过randrange更⾼效,因为它并没有真正构造区间。
1.5 选择随机元素
随机数⽣成器有⼀种常见⽤法,即从⼀个枚举值序列中选择元素,即使这些值并不是数字。random包括⼀个choice()函数,可以从⼀个序列中随机选择。下⾯这个例⼦模拟硬币10000此来统计多少次⾯朝上,多少次⾯朝下。
import random
import itertools
outcomes = {
'heads': 0,
'tails': 0,
}
sides = list(outcomes.keys())
for i in range(10000):
outcomes[random.choice(sides)] += 1
print('Heads:', outcomes['heads'])
print('Tails:', outcomes['tails'])
由于只允许两个结果,所以不必使⽤数字然后再进⾏转换,这⾥对choice()使⽤了单词“heads”(表⽰⾯朝上)和“tails”(表⽰⾯朝下)。结果以表格形式存储在⼀个字典中,使⽤结果名作为键。
1.6 排列
要模拟⼀个扑克牌游戏,需要把⼀副牌混起来,然后向玩家发牌,同⼀张牌不能多次使⽤。使⽤choice()可能导致同⼀张牌被发出两次,所以,可以⽤shuffle()来洗牌,然后在发各张牌时删除所发的牌。
import random
import itertools
FACE_CARDS = ('J', 'Q', 'K', 'A')
SUITS = ('H', 'D', 'C', 'S')
def new_deck():
return [
# Always use 2 places for the value, so the strings
# are a consistent width.
'{:>2}{}'.format(*c)
for c in itertools.product(
itertools.chain(range(2, 11), FACE_CARDS),
SUITS,
)
]
def show_deck(deck):
p_deck = deck[:]
while p_deck:
row = p_deck[:13]
p_deck = p_deck[13:]
for j in row:
print(j, end='')
# Make a new deck, with the cards in order
deck = new_deck()
print('Initial deck:')
show_deck(deck)
# Shuffle the deck to randomize the order
random.shuffle(deck)
print('\nShuffled deck:')
show_deck(deck)
# Deal 4 hands of 5 cards each
hands = [[], [], [], []]
for i in range(5):
for h in hands:
h.append(deck.pop())
# Show the hands
print('\nHands:')
for n, h in enumerate(hands):
print('{}:'.format(n + 1), end='')
for c in h:
print(c, end='')
print()
# Show the remaining deck
print('\nRemaining deck:')
show_deck(deck)
这些扑克牌被表⽰为字符串,包括⾯值和⼀个表⽰花⾊的字母。要创建发出的“⼀⼿牌”,可以⼀次向4个列表分别增加⼀张牌,然后从这副牌中将发出的牌删除,使这些牌不会再次发出。
1.7 采样
很多模拟需要从⼤量输⼊值中得到随机样本。sample()函数可以⽣成⽆重复值的样本,并且不会修改输⼊序列。下⾯的例⼦会打印系统字典中单词的⼀个随机样本。
<
pear
apricot
grape
pineapple
apple
peach
banana
plum
watermelon
lemon
orange
mango
strawberry
Demo.py
import random
with open('', 'rt') as f:
words = f.readlines()
words = [w.rstrip() for w in words]
for w in random.sample(words, 5):
print(w)
第⼀次:
第⼆次:
1.8 多个并发⽣成器
除了模块级函数,random还包括⼀个Random类以管理多个随机数⽣成器的内部状态。之前介绍的所有函数都可以作为Random实例的⽅法得到,并且每个实例都可以被单独初始化和使⽤,⽽不会⼲扰其他实例返回的值。
import random
import time
print('Default initializiation:\n')
r1 = random.Random()
python生成1到100之间随机数r2 = random.Random()
for i in range(3):
print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))
print('\nSame seed:\n')
seed = time.time()
r1 = random.Random(seed)
r2 = random.Random(seed)
for i in range(3):
print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))
如果系统上设置了很好的原⽣随机值种⼦,那么实例会有独特的初始状态。不过,如果没有⼀个好的平台随机值⽣成器,那么不同实例往往会以当前时间作为种⼦,并因此⽣成相同的值。
1.9 SystemRandom
有些操作系统提供了⼀个随机数⽣成器,可以访问更多能引⼊⽣成器的信息源。random通SystemRandom类提供了这个特性,该类与Random的API相同,不过使⽤os.urandom()⽣成值,该值
会构成所有其他算法的基础。
import random
import time
print('Default initializiation:\n')
r1 = random.SystemRandom()
r2 = random.SystemRandom()
for i in range(3):
print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))
print('\nSame seed:\n')
seed = time.time()
r1 = random.SystemRandom(seed)
r2 = random.SystemRandom(seed)
for i in range(3):
print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))
SystemRandom产⽣的序列是不可再⽣的,因为其随机性来⾃系统,⽽不是来⾃软件状态(实际上,seed()和setstate()根本不起作⽤)。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。