frequentism-and-bayesianism-chs
frequentism-and-bayesianism-chs
科学工作者学习统计学的第一件事儿是要知道有两种不同的方法论:频率主义和贝叶斯主义。尽管这点很重要,但很多科学工作者从来没有机会认识两者的差异,及其产生结果的不同。本文的目的是综合频率主义和贝叶斯主义的理论与实践内容,让科学工作者在数据分析之前做出更好的选择。
开始我将通过理论来论述两者区别,之后用Python代码演示两者在应用中的差异。
频率主义 VS 贝叶斯主义: 理论之争
频率主义与贝叶斯主义的本质之争是对概率定义的差异。
频率主义认为概率是表示有限次的重复测量 。假设我多次测量某个星星的亮度(光量子通量)(F) 时(假设星星通量不会变化),由于测量误差每次得到不同的测量值。在多次测量的前提下,某个变量的频率 指的是测量变量的概率。频率主义认为概率本质上是与频率相关的事件 。因此,一个纯粹的频率主义者会认为,讨论星星真实亮度的概率是没啥意义的,因为真实亮度其实是固定值,也就是说讨论一个固定值的频率分布是瞎扯淡。
贝叶斯理论认为,概率的概念应该被扩展为对一个命题信任的程度 。贝叶斯理论会说测量概率为P(F)的星星亮度F:虽然概率确实能够通过大量重复实验获取的频率测得,但是这并非频率的本质。概率是一个由个人经验决定测量结果的主观命题。贝叶斯理论认为概率本质上与我们对事件的掌握程度有关 。贝叶斯理论认为人们可以在一个固定的范围内讨论星星真实亮度的概率。概率也会调整我们对先验信息和/或已有数据的认识。(概率会改变常识)
奇怪的是理论争议不大,但是在实际的数据分析中会产生极大差异。下面我会给出一个实际案例的两种理论实现,用Python演示。
频率理论与贝叶斯理论的实际应用: 光量子计量
让我们看一个简单问题,然后比较一下两种方法的差异。这儿得有点儿数学公式,不过我不会入得特别深哈。如果你想深入,你可以考虑一下练练教材4-5章的内容。
研究对象: 简易光量子计量方法
想象一下我们拿着望远镜,观察遥远的星星传来的无尽星光。首先,让我们假设星星的真实亮度是固定值,不会随时间变化。用常量Ftrue 表示(我们还将忽略大气层的影响,以及其他系统性误差)。我们假设用望远镜进行了N次测量,第ith 次测量报道了观察到的亮度Fi 和误差ei。
问题是有了这些测量值D={Fi,ei},真实亮度Ftrue的最佳估计值是多少?
(关于测量误差:如果假设测量误差是按正态分布。频率主义者的观点是ei是在大量重复**实验**条件下单次测量的标准差。而贝叶斯理论认为ei是按照我们以往的测量经验描述的(正态)概率分布的标准差。)
我们用Python随机生成一些数据来演示两种理论的差异。由于测量是按次计数的离散事件,我们可以使用泊松分布做演示:
# Generating some simple photon count data
import numpy as np
from scipy import stats
np.random.seed(1) # for repeatability F_true = 1000 # true flux, say number of photons measured in 1 second
N = 50 # number of measurements
F = stats.poisson(F_true).rvs(N) # N measurements of the flux
e = np.sqrt(F) # errors on Poisson counts estimated via square root
现在让我们为”测量“值做个简单的图形:
get_ipython().magic(u'matplotlib inline')
import matplotlib.pyplot as plt fig, ax = plt.subplots()
ax.errorbar(F, np.arange(N), xerr=e, fmt='ok', ecolor='gray', alpha=0.5)
ax.vlines([F_true], 0, N, linewidth=5, alpha=0.2)
ax.set_xlabel("Flux");ax.set_ylabel("measurement number");
用标准平方根法则对泊松分布进行分析,可以看到每次测量值的误差都不同。上面的例子中我们是先知道真实值Ftrue的,但是实际问题是:只给测量值和误差,怎么找到真实值的最佳估计值?
下面让我们来看看两种理论的不同解决方案。
简易光量子计量的频率主义方法
我们用频率主义中经典的似然估计方法开始。对应某一次测量值Di=(Fi,ei),以前面假设的正态分布误差ei为标准差,该事件在真实值Ftrue已知的条件下发生的概率分布满足:
公式应该读作“在Ftrue条件下事件Di发生的概率...”,是个均值Ftrue、标准差为ei的正态分布。
我们通过计算每个观测值概率的乘积来构建似然函数。
其中,D={Di}表示整个测量事件。因为似然估计值可能非常小,通常更方便的做法是取对数。
我们这么做是为了确定Ftrue的极大似然估计值。由于问题很简单,所以最大值也容易算(比如通过微分求极值dlogL/dFtrue=0)。下面是Ftrue的极大似然估计值:
特殊情况:当所有的测量误差ei相等时,可以推出
也就是说,当误差相等时,Fest等于观测值的期望,这与直觉一致。
我们可以进一步研究下这么估计的误差。按照频率主义方法,可以通过李雅普诺夫定理将最大似然函数的曲线进行正态近似;在这个简单的例子中也可以容易解决。正态近似的标准差是:
这个结果很容易计算;让我们估计一些我们的数据:
w = 1. / e ** 2
print("""
F_true = {0}
F_est = {1:.0f} +/- {2:.0f} (based on {3} measurements)
""".format(F_true, (w * F).sum() / w.sum(), w.sum() ** -0.5, N))
F_true = 1000
F_est = 998 +/- 4 (based on 50 measurements)
可以看出,以50次测量得到的观测值为输入,得出我们的估计误差在千分之4。
简易光量子计量的贝叶斯方法
你可能认为,如果按照贝叶斯方法,通篇都得使用概率计算。我们真正想计算的其实是我们对参数的主观认识,在本例中就是:
可以看出这与频率主义完成相反,要对Ftrue这样的固定值建模求解,概率做为模型参数没有任何意义。然而,贝叶斯主义却完全可以接受。
贝叶斯主义使用贝叶斯定理这一基本概率论公式:
虽然贝叶斯定理这一法则本身没有争议,贝叶斯主义的名字就从那儿来,但是贝叶斯主义对概率有争议的解释却是暗含在法则的P(Ftrue | D)之中。
让我们仔细看看公式中的术语:
- P(Ftrue | D): 后验概率,是在已获得的数据条件下模型参数的概率:这是我们想要计算的。
- P(D | Ftrue): 相似度,与上面频率主义的似然估计L(D | Ftrue)成正比。
- P(Ftrue): 先验概率,在观察数据D之前我们对事件不确定性的认识。
- P(D): 标准化常量,对实际数量进行简单标准化。
如果我们设置P(Ftrue)∝1(扁平先验,flat prior),那么会发现
也就是说贝叶斯主义的概率是频率主义似然估计结果的最大值!因此,遑论两种理论的差异,我们会发现(至少是简单问题)两种估计是等价的。
什么叫先验概率?
你会发现,我为了图省事儿,先验概率P(Ftrue)没解释清楚。先验概率允许在计算中包含其他有用的信息,实际应用中用多种测量方法组合对某一事件进行评估是非常有用的(比如宇宙成因的参数估计)。然而,确实先验概率的必要性也是贝叶斯分析的争议之一。
当先验事实不存在时,频率主义者会说先验概率不靠谱。尽管用一个未知先验概率更简单,像前面提到那个先验概率常量,但是也会有一些意外的微妙之处。很多实验表明,真正的未知先验概率是不存在的!频率主义者认为主观选择先验概率会偏离结果,不能进行统计数据分析。
贝叶斯主义者认为频率主义解决不了问题,只想简单的避开。在确定(隐含的)先验概率这点上,频率主义经常被简单地看作贝叶斯主义理论的特殊情形:贝叶斯主义会要求最好让隐含变成明确,即使这种选择可能包含主观性。
光量子计量:贝叶斯方法
离开这些理论之争,让我们看看贝叶斯主义的实际计算结果。因为只考虑一个参数,可以将后验概率P(Ftrue | D)当作Ftrue的函数计算:这个分布反映了我们对Ftrue分观布主的认识。但是随着模型规模的增长,这种方法就变得难以把握。因此,贝叶斯主义计算方法常常依赖于抽样方法,如蒙特卡罗马尔可夫链(MCMC)。
这里不细究MCMC的理论知识,我用Dan Foreman-Mackey的Python emcee包做一个简单的应用。目标是产生一堆满足后验概率分布的点,用这些点来确定我们问题的答案。
要演示MCMC,我们用Python定义先验概率P(Ftrue),似然估计值P(D | Ftrue),以及后验概率P(Ftrue | D)。我们的模型是一维的,但是为了处理多维模型,我们要定义参数数组θ,在我们的例子中就是θ=[Ftrue]:
def log_prior(theta):
return 1 # flat prior def log_likelihood(theta, F, e):
return -0.5 * np.sum(np.log(2 * np.pi * e ** 2)
+ (F - theta[0]) ** 2 / e ** 2) def log_posterior(theta, F, e):
return log_prior(theta) + log_likelihood(theta, F, e)
现在我们开始解决问题,产生随机数来猜测这些马尔可夫链上的点。
ndim = 1 # number of parameters in the model
nwalkers = 50 # number of MCMC walkers
nburn = 1000 # "burn-in" period to let chains stabilize
nsteps = 2000 # number of MCMC steps to take # we'll start at random locations between 0 and 2000
starting_guesses = 2000 * np.random.rand(nwalkers, ndim) import emcee
sampler = emcee.EnsembleSampler(nwalkers, ndim, log_posterior, args=[F, e])
sampler.run_mcmc(starting_guesses, nsteps) sample = sampler.chain # shape = (nwalkers, nsteps, ndim)
sample = sampler.chain[:, nburn:, :].ravel() # discard burn-in points
如果都能正常运行,数值sample
会包含满足后验概率分布的50000个点。让我们画出来看看:
# plot a histogram of the sample
plt.hist(sample, bins=50, histtype="stepfilled", alpha=0.3, normed=True) # plot a best-fit Gaussian
F_fit = np.linspace(975, 1025)
pdf = stats.norm(np.mean(sample), np.std(sample)).pdf(F_fit) plt.plot(F_fit, pdf, '-k')
plt.xlabel("F"); plt.ylabel("P(F)")
<matplotlib.text.Text at 0x7f061dec3f90>
我们从(正态)后验概率分布得到一样本。后验概率的期望和标准差是由前面的频率主义极大似然估计得来的:
print("""
F_true = {0}
F_est = {1:.0f} +/- {2:.0f} (based on {3} measurements)
""".format(F_true, np.mean(sample), np.std(sample), N))
F_true = 1000
F_est = 998 +/- 4 (based on 50 measurements)
可以看出,在简单情况下,贝叶斯主义和频率主义两种方法的结果相同!
分析
现在,你可能认为贝叶斯主义的复杂性没啥必要,这个例子已经充分证明了。其实,用一个仿射不变MCMC综合样本发生器来模拟这样一个简单的一维正态分布,实在是杀鸡用牛刀,但是这么做的目的是要表明该方法同样适用于多维度的复杂后验概率情形,也能在复杂条件下提供似然估计不可能提供的优美的结果。
另外,你还可能注意到一个小伎俩:最后,我们用来频率主义方法来描述后验概率样本!当我们计算样本期望和标准差的时候,我们使用了一个标准的频率主义方法来刻画后验概率分布。用纯贝叶斯理论分析这个问题的结果可能要包含后验概率本身(比如,它的类似样本)。也就是说,在纯贝叶斯主义的结果中,问题不是一个简单的数值和误差,而是后验概率分布和模型参数!
增加一个维度:研究更复杂的模型
让我们看一个更复杂的情况,再比较一下频率主义和贝叶斯主义的结果。前面我们假设星星是静止的,现在假设我们观察的天体是一个随机变量;就是说它会随着时间变化(就是类星体那种)。
我们将用双参数正态分布来表示这个天体:θ=[μ,σ],其中,μ是期望值,σ是天体本征变量的标准差。于是我们每次观察时真实亮度概率的模型:
现在,我们再考虑N次观察里每次的误差。可以这么产生:
np.random.seed(42) # for reproducibility
N = 100 # we'll use more samples for the more complicated model
mu_true, sigma_true = 1000, 15 # stochastic flux model F_true = stats.norm(mu_true, sigma_true).rvs(N) # (unknown) true flux
F = stats.poisson(F_true).rvs() # observed flux: true flux plus Poisson errors.
e = np.sqrt(F) # root-N error, as above
可变条件下的光量子计量:频率主义方法
似然估计结果是本征分布与误差分布的卷积,可以得出
与前面类似,我们可以通过求微分解出似然估计的最大值,即μ的最佳估计:
这里有个问题:参数μ的值依赖于σ的值。两者具有相关性,因此我们不能直接使用频率主义的解析方法求解。
然而,我们能用数值分析计算来解极大似然估计值。这里我们用Scipy里面的最优化工具optimize:
def log_likelihood(theta, F, e):
return -0.5 * np.sum(np.log(2 * np.pi * (theta[1] ** 2 + e ** 2))
+ (F - theta[0]) ** 2 / (theta[1] ** 2 + e ** 2)) # maximize likelihood <--> minimize negative likelihood
def neg_log_likelihood(theta, F, e):
return -log_likelihood(theta, F, e) from scipy import optimize
theta_guess = [900, 5]
theta_est = optimize.fmin(neg_log_likelihood, theta_guess, args=(F, e))
print("""
Maximum likelihood estimate for {0} data points:
mu={theta[0]:.0f}, sigma={theta[1]:.0f}
""".format(N, theta=theta_est))
Optimization terminated successfully.
Current function value: 502.839505
Iterations: 58
Function evaluations: 114 Maximum likelihood estimate for 100 data points:
mu=999, sigma=19
Scipy给出了μ和σ的极大似然估计值的最佳组合。但是问题才解决一半:我们需要确定答案的置信区间,也就是我们要计算μ和σ的误差。
在频率主义模式中有不同的方法来确定误差。如前所述,我们可以用正态近似去拟合最大似然估计和协方差矩阵(这里我们应该用数值分析而不是解析方法)。另外,我们可以计算统计量如χ2和χ2dof,然后使用卡方检验来决定置信区间,还需要假设似然估计具有正态性。我们也可以使用随机抽样方法如Jackknife或者Bootstrap,为了研究结果的确定程度,使输入数据的随机样本的似然估计最大化。
这些方法都行,但是每种方法都有各自的假设前提和特点。我们用Python的astroML包里面的basic bootstrap resampler:
from astroML.resample import bootstrap def fit_samples(sample):
# sample is an array of size [n_bootstraps, n_samples]
# compute the maximum likelihood for each bootstrap.
return np.array([optimize.fmin(neg_log_likelihood, theta_guess,
args=(F, np.sqrt(F)), disp=0)
for F in sample]) samples = bootstrap(F, 1000, fit_samples) # 1000 bootstrap resamplings
和前面的贝叶斯后验概率的MCMC方法类似,我们将计算样本期望值和标准差来确定参数误差。
mu_samp = samples[:, 0]
sig_samp = abs(samples[:, 1]) print " mu = {0:.0f} +/- {1:.0f}".format(mu_samp.mean(), mu_samp.std())
print " sigma = {0:.0f} +/- {1:.0f}".format(sig_samp.mean(), sig_samp.std())
mu = 999 +/- 4
sigma = 18 +/- 5
我得说明bootstrap resampling的细究有大堆资料可供参考,这里粗略地说明一下这个方法的特点。最明显的地方就是误差需要是相关的、非正态的,但是这两个特点都不能通过简单的计算每个模型参数的均值和方差反映出来。然而,我相信这给频率主义提供的基本的解题思路。
可变条件下的光量子计量:贝叶斯主义方法
贝叶斯主义对这个问题的解决方法可之前那个问题基本雷同,我们可以把上面的代码简单改改就行。
def log_prior(theta):
# sigma needs to be positive.
if theta[1] <= 0:
return -np.inf
else:
return 0 def log_posterior(theta, F, e):
return log_prior(theta) + log_likelihood(theta, F, e) # same setup as above:
ndim, nwalkers = 2, 50
nsteps, nburn = 2000, 1000 starting_guesses = np.random.rand(nwalkers, ndim)
starting_guesses[:, 0] *= 2000 # start mu between 0 and 2000
starting_guesses[:, 1] *= 20 # start sigma between 0 and 20 sampler = emcee.EnsembleSampler(nwalkers, ndim, log_posterior, args=[F, e])
sampler.run_mcmc(starting_guesses, nsteps) sample = sampler.chain # shape = (nwalkers, nsteps, ndim)
sample = sampler.chain[:, nburn:, :].reshape(-1, 2)
现在有了样本,我们可以利用astroML包方便的功能来画出轨迹图,并用等高线描述1、2标准差的情况:
from astroML.plotting import plot_mcmc
fig = plt.figure()
ax = plot_mcmc(sample.T, fig=fig, labels=[r'$\mu$', r'$\sigma$'], colors='k')
ax[0].plot(sample[:, 0], sample[:, 1], ',k', alpha=0.1)
ax[0].plot([mu_true], [sigma_true], 'o', color='red', ms=10);
红点显示在真实值附近(在前述问题条件下),等高线显示了1、2个标准差的置信区间情况(68%和95%置信水平)。
这里要注意σ=0与两个标准差的情况一致:也就是说,依赖于你自己对确定性的临界值感觉,我们的数据不足以保证一个定点数据源概率的置信区间。
另外,后验概率确实是非正态的:可以通过垂直方向的对称性来看。也就意味着用频率主义的正态近似不会将真实的不确定性反映到结果中。对频率主义者来说这不是啥事儿(频率主义模式有方法会考虑到非正态性),但是频率主义方法的绝大多数使用者都直接或间接地使用了正态分布的假设。贝叶斯方法一般不需要这个假设。
(先验概率:有些观点在确定σ的扁平先验时与本文的计算方式有轻微差异:它们认为,在处理像σ这样的比例因子时,扁平先验不是必须的。[Jeffreys 先验](http://en.wikipedia.org/wiki/Jeffreys_prior)的一些有趣的论述更容易接受。我认为Jeffreys不太适合,因为σ不是一个真实的比例因子(比如,正态分布也会影响ei)。关于这个问题,我将参考其他专业人士的观点。我个人认为,这些小问题往往是贝叶斯主义与频率主义争论的焦点)。
结论
我希望我已经通过这篇文章展示了频率主义与贝叶斯主义根本的区别,导致两者本质上对同样问题有着不同的解释,然而彼此却经常可以产生相似甚至相同的结果。
两者差异总结如下:
- 频率主义认为概率与事实或假想事件的频率有关。
- 贝叶斯主义认为概率是对事件认识程度的度量。
- 频率主义通常使用点估计和极大似然估计方法进行分析。
- 贝叶斯主义通常直接的计算后验概率,或者通过一些MCMC抽样的方法计算。
处理简单问题时,两种方法会产生近似的结果。但当数据和模型越来越复杂时,两种方法会有天壤之别。在以后的文章中,我会显示一两个更复杂的案例。继续关注噢!
Update: 看下一篇文章:频率主义与贝叶斯主义 II: 当结果不同时
frequentism-and-bayesianism-chs的更多相关文章
- The Model Complexity Myth
The Model Complexity Myth (or, Yes You Can Fit Models With More Parameters Than Data Points) An oft- ...
- AutoCAD 2007在win8.1安装出现——错误1606。无法访问网络位置Autodesk\AutoCAD2007\R17.0\chs\的解决
环境win 8.1 64位,AutoCAD 2007 安装CAD2007,一开始安装就出错,提示:错误1606.无法访问网络位置Autodesk\AutoCAD2007\R17.0\chs\ 百度之后 ...
- CHS与LBA之间转换程序
原理及介绍来自维基百科 http://zh.wikipedia.org/wiki/%E9%82%8F%E8%BC%AF%E5%8D%80%E5%A1%8A%E4%BD%8D%E5%9D%80 个人用的 ...
- LBA和CHS转换
磁盘填充,先填满一个柱面之后,再填下一个柱面.LBA是从0开始的. LBA = (C-CS)*HPC*SPT + (H-HS)*SPT + (S-SS) C, H, S: 当前的CHS值 CS, HS ...
- 读取磁盘:CHS方式
读取磁盘:CHS方式 BIOS读取磁盘 读取磁盘也是调用BIOS: 中断命令: INT 13H 读取扇区的入口参数为 AH = 02H 功能参数,读取扇区 AL = 扇区数 CH = 柱面 CL = ...
- 为什么一定要调用 setlocale 呢? 因为在 C/C++ 语言标准中定义了其运行时的字符集环境为 "C" ,也就是 ASCII 字符集的一个子集。使用setlocal改变整个应用程序的字符集编码方式(wcstombs使用前要设置 setlocale (LC_ALL, "chs"); )
setlocale 配置地域化信息. 语法: string setlocale(string category, string locale); 返回值: 字符串 函数种类: 操作系统与环境 内容 ...
- setlocale同mbstowcs函数的关系(VS2008下setlocale(LC_ALL, "chs")可以执行成功,BCB使用setlocale(LC_ALL, "Chinese (Simplified)_People's Republic of China"),linux上locale别名表大概在 /usr/lib/X11/locale/locale.alias)
序中,如果要将ASCII码字符串转换为宽字符(Unicode),可以利用标准C的mbstowcs函数. 微软在MSDN中有示例,如下: 然而,这段代码在处理含有汉字的字符串时就会出现问题.比如将: w ...
- C++的中英文字符串表示(string,wstring),使用wcout.imbue(std::locale("chs"));本地化解析编码
在C++中字符串类的string的模板原型是basic_string template <class _Elem, class traits = char_traits<_Elem> ...
- 硬盘LBA 和CHS的关系(转)
磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数 l 磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头:l 磁道(track)数:磁 ...
- Win8.1 MSDN各版本下载(64位/32位,简体中文,繁体中文,英文),X86&X64,EN,CHS,CHT
英文64位ed2k://|file|en_windows_8_1_x64_dvd_2707217.iso|3899295744|8E604054013D21209B851E41DC19F6F5|/ 英 ...
随机推荐
- 利用JS实现的根据经纬度计算地球上两点之间的距离
最近用到了根据经纬度计算地球表面两点间距离的公式,然后就用JS实现了一下. 计算地球表面两点间的距离大概有两种办法. 第一种是默认地球是一个光滑的球面,然后计算任意两点间的距离,这个距离叫做大圆距 ...
- 一个自定义的C#数据库操作基础类 SqlHelper
SqlHelper其实是我们自己编写的一个类,使用这个类目的就是让使用者更方便.更安全的对数据库的操作,既是除了在SqlHelper类以外的所有类将不用引用对数据库操作的任何类与语句,无须担心数据库的 ...
- 编写高质量代码改善C#程序的157个建议
1.使用StringBuilder或者使用string.Format("{0}{1}{2}{3}", a, b, c, d)拼接字符串. 2.使用默认转型方法,比如使用类型内置的P ...
- Jquery制作可以绑定的表格
//总页数 当前页 可见页 参数 翻页执行后处理的函数 function PageTable(totalPages, currentPage, tableobj, url, where, column ...
- python基础学习笔记第二天 内建方法(s t r)
python的字符串内建函数 str.casefold()将字符串转换成小写,Unicode编码中凡是有对应的小写形式的,都会转换str.center()返回一个原字符串居中,并使用空格填充至长度 w ...
- C基础 那些年用过的奇巧淫技
引言 - 为寻一颗明星 为要寻一颗明星 徐志摩 1924年12月1日<晨报六周年纪念增刊> 我骑著一匹拐腿的瞎马, 向著黑夜里加鞭:—— 向著黑夜里加鞭, 我跨著一匹拐腿的瞎马.// 我冲 ...
- open/fopen read/fread write/fwrite区别
fopen /open区别 UNIX环境下的C 对二进制流文件的读写有两套班子:1) fopen,fread,fwrite ; 2) open, read, write这里简单的介绍一下他们的区别.1 ...
- OracleINSERT提示IGNORE_ROW_ON_DUPKEY_INDEX
OracleINSERT提示IGNORE_ROW_ON_DUPKEY_INDEX insert提示IGNORE_ROW_ON_DUPKEY_INDEX 在 insert into table a() ...
- linux kernel 0.11 setup
setup作用 ①读取参数放在0x90000处. ②将原本在0x10000处的system模块移至0x00000处 ③加载中断描述符表,全局描述符表,进入32位保护模式. 概念 关于实模式和保护模式区 ...
- javascript 关于Date 时间类型 处理方法
上一篇博客中和大家分享了关于 字符串转时间类型 这一篇顺便整理下 javascript 中 Date 类型的一些方法 var time = new Date(); var year=time.getY ...