《编程导论》 CH12 随机算法、概率以及统计
12.1 随机程序
函数random.choice 接受一个非空序列作为参数并返回一个从序列中随机选择的元素。
random中的绝大多数函数都使用函数random.random实现,这个函数会返回0.0和1.0之间的一个随机浮点数。
掷骰子
import random
def rollDie():
"""return an int between 1 and 6"""
return random.choice([1,2,3,4,5,6])
def rollN(n):
result =''
for i in range(n):
result = result + str(rollDie())
print result
rollN(10)
12.2 统计推断和模拟
统计推断:从一个群体中选出的随机样本趋向于表现出和这个群体相同的属性
抛硬币:
def flip(numFlips):
heads = 0.0
for i in range(numFlips):
if random.random()<0.5:
heads += 1
return heads/numFlips
def flipSim(numFlipsPerTrial,numTrials):
fracHeads = []
for i in range(numTrials):
fracHeads.append(flip(numFlipsPerTrial))
mean = sum(fracHeads)/len(fracHeads)
return mean
print flipSim(100,1)
print flipSim(100,1)
print flipSim(100,100)
print flipSim(100,100)
print flipSim(100,100000)
print flipSim(100,100000)
大数定律——>避免赌徒谬误、比例VS数量
下面的函数flipPlot会生成一些曲线来证明大数原则确实起作用了。倒数第二句random.seed(0)确保代码执行时random.random每次生成的伪随机数序列都是相同的,这样调试起来会比较方便。
绘制抛硬币的结果:
def flipPlot(minExp,maxExp):
"""assume minExp&maxExp are possitive integers and minExp
pylab.plot(xAxis,diffs,'bo')可以让程序只绘制点
pylab.semilogx()或者pylab.semilogy()分别让x轴和y轴使用对数刻度。
衡量不同输出之间的分散程度:方差——>标准差
def stdDev(X):
"""assume X is a list of numbers"""
mean = float(sum(X))/len(X)
tot = 0.0
for x in X:
tot += (x - mean)**2
return (tot/len(X))**0.5
可以通过标准差来判断我们得出的结论的可信度。
下面的代码展示了一个flipPlot的修改版本。对于不同的抛掷次数,它会进行多次实验并绘制出abs(heads-tails)的平均值、比例heads/tails以及两者的标准差。
def makePlot(xVals,yVals,title,xLabel,yLabel,style,logX=False,logY=False):
pylab.figure()
pylab.title(title)
pylab.xlabel(xLabel)
pylab.ylabel(yLabel)
pylab.plot(xVals,yVals,style)
if logX:
pylab.semilogx()
if logY:
pylab.semilogy()
def runTrial(numFlips):
numHeads = 0
for n in range(numFlips):
if random.random()<0.5:
numHeads += 1
numTails = numFlips - numHeads
return (numHeads,numTails)
def flipPlot1(minExp,maxExp,numTrials):
ratiosMeans,diffsMeans,ratiosSDs,diffsSDs = [],[],[],[]
xAxis =[]
for exp in range(minExp,maxExp+1):
xAxis.append(2**exp)
for numFlips in xAxis:
ratios = []
diffs =[]
for t in range(numTrials):
numHeads, numTails = runTrial(numFlips)
ratios.append(numHeads/float(numTails))
diffs.append(abs(numHeads - numTails))
ratiosMeans.append(sum(ratios)/float(numTails))
diffsMeans.append(sum(diffs)/float(numTails))
ratiosSDs.append(stdDev(ratios))
diffsSDs.append(stdDev(diffs))
numTrialsString ='('+str(numTrials)+' Trails)'
title = 'Mean Heads/Tails Ratios'+numTrialsString
makePlot(xAxis,ratiosMeans,title,'Number of flips','Mean Heads/Tails','bo',logX=True)
title = 'SD Heads/Tails Ratios'+numTrialsString
makePlot(xAxis,ratiosSDs,title,'Number of flips','Standard Deviation','bo',logX=True,logY=True)
flipPlot1(4,20,20)
正面和反面数量的绝对差值:
title = 'Mean abs(#Heads - #Tails)' + numTrialsString
makePlot(xAxis,diffsMeans,title,'Number of Flips','Mean abs(#Heads-#Tails)','bo',logX=True,logY = True)
title = 'SD abs(#Heads -#Tails)'+numTrialsString
makePlot(xAxis,diffsSDs,title,'Number of Flips','Standard Deviation','bo',logX = True,logY = True)
标准差要结合平均值来看。如果平均值是10亿,而标准差是100,那我们就认为数据很集中。如果平均值是100,而标准差也是100,那我们就认为数据很分散。
变异系数是标准差除以平均值。在处理平均值变化较大的数据集时,变异系数比标准差有意义。
def CV(X):
mean = sum(X)/float(len(X))
try:
return stdDev(X)/mean
except ZeroDivisionError:
return float('nan')