作用:实现了多种类型的伪随机数生成器。
Python版本:1.4及以后版本
random模块基干Mersenne IVister算法提供了一个快速伪随机数生成器。原先开发这个生成器是为了向蒙特卡洛模拟生成输入,Mersenne Twister算法会生成有一个大周期的近均匀分 布的数,以适用于各种类型的应用。
生成随机数
random()函数从所生成的序列返回下一个随机的浮点数值。返回的所有值都落在0< n <1.0区间内。
import random
for i in xrange(5):
print '%04.3f' % random.random(),
print
重复运行这个程序会生成不同的数字序列。
0.929 0.100 0.906 0.075 0.439
[Finished in 0.1s]
要生成一个指定数值区间内的数,则要使用uniform()。
import random
for i in xrange(5):
print '%04.3f' % random.uniform(1, 100),
print
传入最小值和最大值,uniform()会使用公式min + (max - min) * random来调整random() 的返回值。
4.679 66.794 19.423 44.725 5.482
[Finished in 0.1s]
指定种子
每次调用random会生成不同的值,在一个非常大的周期之后数字才会重复。这对于生成惟一值或变化的值很有用,不过有些情况下可能需要提供相同的数据集,从而以相同的方式处理。对此,一种技术是使用一个程序来生成随机值,并保存这些随机值,以便通过一个单独的步骤另行处理。不过,这对于量很大的数据来说可能并不实用,所以random包含了一个seed() 函数,用来初始化伪随机数生成器,使它能生成一个期望的值集。
import random
random.seed(1)
for i in xrange(5):
print '%04.3f' % random.random(),
print
种子(seed)值会控制生成伪随机数所用公式产生的第一个值,由于公式是确定性的,改变种子后也就设置了要生成的整个序列。seed的参数可以是任意可散列对象。默认为使用一个平台特定的随机源(如杲有的话)。否則,如果没有这样一个随机源,则会使用当前时间。
0.134 0.847 0.764 0.255 0.495
[Finished in 0.1s]
保存状态
random使用的伪随机算法的内部状态可以保存,并用于控制后续各轮生成的随机数,继续生成随机数之前恢复前一个状态,这会减少由之前输入得到重复的值或值序列的可能性。getstate函数会返回一些数据,以后可以用setstate利用这些数据重新初始化伪随机数生成器。
import random
import os
import cPickle as pickle
if os.path.exists('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 xrange(3):
print '%04.3f' % random.random(),
print
# Save state for next time
with open('state.dat', 'wb') as f:
pickle.dump(random.getstate(), f)
# Produce more random values
print '\nAfter saving state:'
for i in xrange(3):
print '%04.3f' % random.random(),
print
getstate()返回的数据是一个实现细节,所以这个例子用pickle将数据保存到一个文件,不过可以把它当作一个黑盒。如果程序开始时这个文件存在,则加载原来的状态并继续。每次运行时都会在保存状态之前以及之后生成一些数,以展示恢复状态会导致生成器再次生成同样的值。
No state.dat, seeding
0.134 0.847 0.764
After saving state:
0.255 0.495 0.449
[Finished in 0.1s]
Found state.dat, initializing random module
0.255 0.495 0.449
After saving state:
0.652 0.789 0.094
[Finished in 0.1s]
Found state.dat, initializing random module
0.652 0.789 0.094
After saving state:
0.028 0.836 0.433
[Finished in 0.1s]
随机整数
random将生成浮点数。可以把结果转换为整数,不过直接使用randint生成整数会更方便。
import random
print '[1, 100]:',
for i in xrange(3):
print random.randint(1, 100),
print '\n[-5, 5]:',
for i in xrange(3):
print random.randint(-5, 5),
print
randint的参数是值的闭区间的两端,这些数可以是正数或负数,不过第一个值要小于第二个值.
[1, 100]: 35 39 28
[-5, 5]: -3 4 4
[Finished in 0.1s]
randrange是从区间选择值的一种更一般的形式。
import random
for i in xrange(3):
print random.randrange(0, 101, 5),
print
除了开始值(start)和结束值(stop), randrange还支持一个步长 step 参数,所以它完全等价于从range(start,stop,step)选择一个随机值。不过randrange更高效,因为它并没有真正构造区间。
15 25 85
[Finished in 0.1s]
选择随机元素
随机数生成器有一种常见用法,即从一个枚举值序列中选择元素,即使这些值并不是数字。random包括一个choice函数,可以在一个序列中随机选择。下面这个例子模拟抛硬币10000 次,来统计多少次面朝上,多少次面朝下,
import random
import itertools
outcomes = { 'heads':0,
'tails':0,
}
sides = outcomes.keys()
for i in range(10000):
outcomes[ random.choice(sides) ] += 1
print 'Heads:', outcomes['heads']
print 'Tails:', outcomes['tails']
由于只允许两个结果,所以不必使用数字然后再进行转换,这里对choice使用了单词 “heads”(表示面朝上)和“tails”(表示面朝下)。结果以表格形式存储在一个字典中,使用结果名作为键。
Heads: 5042
Tails: 4958
[Finished in 0.1s]
排列
要模拟一个扑克牌游戏,需要把一副牌混起来,然后向玩家发牌,同一张牌不能多次使用。使用choice可能导致同一张牌被发出两次,所以可以用shuffle()来洗牌,然后在发各张牌时删除所发的牌。
import random
import itertools
FACE_CARDS = ('J', 'Q', 'K', 'A')
SUITS = ('H', 'D', 'C', 'S')
def new_deck():
return list(itertools.product(
itertools.chain(xrange(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 '%2s%s' % j,
print
# 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 xrange(5):
for h in hands:
h.append(deck.pop())
# Show the hands
print '\nHands:'
for n, h in enumerate(hands):
print '%d:' % (n+1),
for c in h:
print '%2s%s' % c,
print
# Show the remaining deck
print '\nRemaining deck:'
show_deck(deck)
这些扑克牌表示为元组,由面值和一个表示花色的字母组成。要创建已发出“一手牌”,可以一次向4个列表分别增加一张牌,然后从这副牌中将其刪除,使这些牌不会再次发出。
Initial deck:
2H 2D 2C 2S 3H 3D 3C 3S 4H 4D 4C 4S 5H
5D 5C 5S 6H 6D 6C 6S 7H 7D 7C 7S 8H 8D
8C 8S 9H 9D 9C 9S 10H 10D 10C 10S JH JD JC
JS QH QD QC QS KH KD KC KS AH AD AC AS
Shuffled deck:
3C 8S QC 5D 2C 9H QH KC AS 4D 5H 10D QS
3S 5S JS AD QD 5C KS 8H 4S 3H 7S 10C 6D
3D 2S 7D 4C 2H 9S 2D 6S 4H 6C AC JD 8D
10H KH KD JC 6H 9C JH 7C 10S 8C AH 9D 7H
Hands:
1: 7H 10S 6H 10H 6C
2: 9D 7C JC 8D 4H
3: AH JH KD JD 6S
4: 8C 9C KH AC 2D
Remaining deck:
3C 8S QC 5D 2C 9H QH KC AS 4D 5H 10D QS
3S 5S JS AD QD 5C KS 8H 4S 3H 7S 10C 6D
3D 2S 7D 4C 2H 9S
[Finished in 0.1s]
采样
很多模拟需要从大量输入值中得到随机样本sample()函数可以生成无重复值的样本,且不会修改输入序列。下面的例子会打印系统字典中单词的一个随机样本。
import random
with open('words.txt', 'rt') as f:
words = f.readlines()
words = [ w.rstrip() for w in words ]
for w in random.sample(words, 5):
print w
生成结果集的算法会考虑輪入的规模和所请求的样本,从而尽可能髙效地生成结果。
docibility
Ituraean
youdendrift
sporidium
pansylike
[Finished in 0.1s]
Ituraean
pansylike
jigamaree
docibility
readingdom
[Finished in 0.1s]
多个并发生成器
除了模块级函数,random还包括一个Random类来管理多个随机数生成器的内部状态。之前介绍的所有函数都可以作为Random实例的方法得到,而且各个实例可以单独初始化和使用,而不会与其他实例返回的值相互干扰。
import random
import time
print 'Default initializiation:\n'
r1 = random.Random()
r2 = random.Random()
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
print '\nSame seed:\n'
seed = time.time()
r1 = random.Random(seed)
r2 = random.Random(seed)
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
如杲系统上设置了很好的内置随机值种子,不同实例会有惟一的初始状态。不过,如果没有一个好的平台随机值生成器,不同实例往往会用当前时间作为种子,因此会生成相同的值。
Default initializiation:
0.189 0.307
0.466 0.328
0.020 0.757
Same seed:
0.510 0.510
0.981 0.981
0.679 0.679
[Finished in 0.1s]
为了确保生成器从随机周期的不同部分生成值,可以使用jumpahead调整其中一个生成器的初始状态。
Default initializiation:
0.189 0.307
0.466 0.328
0.020 0.757
Same seed:
0.510 0.510
0.981 0.981
0.679 0.679
[Finished in 0.1s]
SystemRandom
有些操作系统提供了一个随机数生成器,可以访问更多能够引入生成器的信息源。 random通过SystemRandom类提供了这个特性,这个类与Random的API相同,不过使用os.urandom()生成值,这构成了所有其他算法的基础。
import random
import time
print 'Default initializiation:\n'
r1 = random.SystemRandom()
r2 = random.SystemRandom()
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
print '\nSame seed:\n'
seed = time.time()
r1 = random.SystemRandom(seed)
r2 = random.SystemRandom(seed)
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
SystemRandom产生的序列是不可再生的,因为其随机性来自系统,而不是来自软件状态 (实际上,seed()和setstate()根本不起作用).
Default initializiation:
0.945 0.201
0.767 0.295
0.984 0.383
Same seed:
0.584 0.324
0.598 0.624
0.400 0.310
[Finished in 0.1s]
非均匀分布
random生成的值为均匀分布,这对于很多用途来说非常有用,不过,另外一些分布可以更准确地对特定情况建模。random模块还包含一些函数来生成这样一些分布的值。这里将列出 这些分布,但是并不打算详细介绍,因为它们往往只在特定条件下使用,而且需要更复杂的例 子来说明。
正态分布
正态分布(normal distribution)常用于非均匀的连续值,如梯度、髙度、重置等等.正态 分布产生的曲线有一个独特形状,所以被昵称为“钟形曲线”。random包含两个函数可以生成 正态分布的值,分別是normalvariate和稍快一些的gauss。(正态分布也称为髙斯分布。) 还有一个相关的函数lognormvariate,它可以生成对数呈正态分布的伪随机值。对数正态分布适用于多个不交互随机变量的积。
近似分布
三角分布用于小样本的近似分布。三角分布的“曲线”中,低点在已知的最小和最大值,在模式值处有一个髙点,这要根据“最接近”的结果(由triangularO的模式参数反映)来估计。
指数分布
expovariate可以生成一个指数分布,这对于模拟到达或间隔时间值用于齐次泊松过程会很有用,如放射衰变速度或到达Web服务器的请求。很多可观察的现象都适用帕累托分布或幂律分布,这个分布因Chris Anderson的“长尾效应”而普及。paretovariatc()函数对于槙拟资源分配很有用(人的财宫、音乐家的需求、对博客的关注,等等)。
角分布
米塞斯分布或圆正态分布(由vonmisesvariate生成)用于计算周期值的概率,如角度、 日历日期和时间。
大小分布
betavariate生成Beta分布的值,常用于贝叶斯统计和应用,如任务持续时间建模。 gammavariate()生成的伽玛分布用于对事物的大小建模,如等待时间、雨量和计算错误。 weibullvariate计算的韦伯分布用于故障分析、工业工程和天气预报。它描述了粒子或其 他离散对象的大小分布。