第六章 决策分析
话说,美国有一档节目,叫做showcase,游戏规则是这个样子:给两个箱子,箱子中装着奖品,两个人分别找一个箱子,开始猜这个箱子中所有奖品价格之和,谁猜得最接近谁获胜,猜超出了实际价钱的,判输。
作为一个bayesian学派的信徒,我们需要考虑几个问题:
1.当看到奖品之前,竞猜者对于箱子的价值,应该具有什么样的先验信念?
2.当看到这些奖品后,竞猜者应该怎样更新这些信念?
3.基于这些后验分布,竞猜者该如何出价?
第三个问题也就是决策分析的内容了,给一个后验分布,我先最大化竞猜者的期望回馈,然后进行出价。
下面开始分析了,对于第一个问题,我该具有什么样的先验信念? 多亏showcase节目的参与者都保留了自己出价的记录,根据这份记录,我们得到了一张价格_人数图,归一化并使用KDE(Gaussian kernel density estimation)平滑后就得到价格的概率分布,如下图所示,紫色的是showcase1,蓝色的是showcase2
图1 showcase的出价分布图
现在作为竞猜者,我可以使用这个分布图来量化自己对于竞猜标的的先验信念。之后就需要对我的这些先验信念进行更新,这时我们需要考虑两点:
(1) 我们需要考虑什么数据,我们怎么样来量化它?
(2)我们能否计算一个似然函数?也就是说,对于每个价格的假设值,我们能够计算出这个数据的条件似然值?
为了方便建模,我们把竞猜者看作是一种出价错误率已知的出价机器,它一看到showcase就出价,我们称它出的价是guess,那么我们就要回答,如果showcase的实际价钱是price,竞猜者的估值是guess的似然值是多大?或者换种方式: error = price - guess 那么竞猜者出现变差的数值是error的似然值多大? 我们还需要利用历史数据,假设 diff = price - bid 那么diff的累积分布曲线是:
图2 diff的积累分布曲线
然后,我们利用这个曲线来量化竞猜者的估价是否靠谱,这里,我们直接把他们的出价当做估价,尽管严格来说,由于出价策略的影响,竞猜者的实际出价和他们的估价并不一定相等。 此外,我们还需要提出一些假设,这里我们假设error的均值为0,方差为diff的方差。
其中,self.cdf_diff就是图2
接下来就是进行后验分布的更新了,Player提供了一个MakeBeliefs(self,guess)函数,输入竞猜者的估价,然后计算后验分布,计算后验分布的过程是:将每个假设价格的似然值,分别乘以先验概率
相关函数如下:
class Suite(Pmf):
"""Represents a suite of hypotheses and their probabilities."""
def Update(self, data):
"""Updates each hypothesis based on the data.
data: any representation of the data
returns: the normalizing constant
"""
for hypo in self.Values():
like = self.Likelihood(data, hypo)
self.Mult(hypo, like)
return self.Normalize()
class Pdf(object):
"""Represents a probability density function (PDF)."""
def Density(self, x):
"""Evaluates this Pdf at x.
Returns: float probability density
"""
raise UnimplementedMethodException()
def MakePmf(self, xs, name=''):
"""Makes a discrete version of this Pdf, evaluated at xs.
xs: equally-spaced sequence of values
Returns: new Pmf
"""
pmf = Pmf(name=name)
for x in xs:
pmf.Set(x, self.Density(x))
pmf.Normalize()
return pm
class GaussianPdf(Pdf):
"""Represents the PDF of a Gaussian distribution."""
def __init__(self, mu, sigma):
"""Constructs a Gaussian Pdf with given mu and sigma.
mu: mean
sigma: standard deviation
"""
self.mu = mu
self.sigma = sigma
def Density(self, x):
"""Evaluates this Pdf at x.
Returns: float probability density
"""
return EvalGaussianPdf(x, self.mu, self.sigma)
class EstimatedPdf(Pdf):
"""Represents a PDF estimated by KDE."""
def __init__(self, sample):
"""Estimates the density function based on a sample.
sample: sequence of data
"""
self.kde = scipy.stats.gaussian_kde(sample)
def Density(self, x):
"""Evaluates this Pdf at x.
Returns: float probability density
"""
return self.kde.evaluate(x)
def MakePmf(self, xs, name=''):
ps = self.kde.evaluate(xs)
pmf = MakePmfFromItems(zip(xs, ps), name=name)
return pmf
def MakePmfFromItems(t, name=''):
"""Makes a PMF from a sequence of value-probability pairs
Args:
t: sequence of value-probability pairs
name: string name for this PMF
Returns:
Pmf object
"""
pmf = Pmf(dict(t), name)
pmf.Normalize()
return pmf