贝叶斯模型
要建立一个贝叶斯模型,我们需要确定模型的输出(outcome)符合什么分布,这意味着我们需要选择一个似然函数。
eg.
$$ height \sim Normal(\mu, \sigma) $$
如何选择似然函数
选择似然函数的时候,要考虑:
- 数据本身的情况,比如是整数还是浮点数,是否有上下界等(Epistemological, which means philosophy behind knowledge)。
- 要描述的对象在现实中是如何分布的,比如大量随机影响下,数据常常(天然地)呈正态分布(Ontological, which means the nature of the world)。
所选择的似然函数常常会需要传入参数(parameters),对于每个参数,我们需要在一开始估计它的分布,这个分布称为这个参数的先验(prior)。
eg.
$$ \sigma \sim Exp(?) $$
有些参数可能和你所知道的其他输入有关,此时,这些输入称为自变量(predictor variable)。
eg.
$$ \mu = \alpha + \beta \times (weight - 150) $$
这里的 $\alpha$ 和 $\beta$ 是新增加的参数,而 $weight$ 就是自变量。
所以我们整个的模型就是:
$$ \displaylines { height & \sim & Normal(\mu, \sigma) \\ \mu & = & \alpha + \beta \times weight \\ \alpha & \sim & Normal(?, ?) \\ \beta & \sim & Normal(?, ?) \\ \sigma & \sim & Exp(?) } $$
现在我们需要确定模型中这些 $?$ 的值,并验证这些值是相对好的,这个过程称为 prior predictive check。
Prior predictive check
Prior predictive check 的目的是检查模型中的先验分布是否合理。
一般来说 prior predictive check 的方法是选定一组 prior,然后用这组 prior 生成一些数据,看这些数据是否合理。
比如以上面的例子来说,如果取以下的 prior:
$$ \displaylines { height & \sim & Normal(\mu, \sigma) \\ \mu & = & \alpha + \beta \times (weight - 150) \\ \alpha & \sim & Normal(0, 1) \\ \beta & \sim & Normal(0, 1) \\ \sigma & \sim & Exp(1) } $$
那么模型可以生成(大量的)负数的 height,这显然是不合理的。
根据经验,人的身高大约在 165 厘米左右,且身高和体重呈正相关,因此一组更好的 prior 可以是:
$$ \displaylines { height & \sim & Normal(\mu, \sigma) \\ \mu & = & \alpha + \beta \times (weight - 60) \\ \alpha & \sim & Normal(165, 20) \\ \beta & \sim & Normal(0.5, 0.2) \\ \sigma & \sim & Exp(1) } $$
当然你也可以搜集更多的知识选择更好的 prior,或者换用更合理的分布函数,比如让 $\beta \sim \text{log-Normal}(?, ?)$。
如何学习参数的值
一个常用的方法是使用 MCMC(Markov chain Monte Carlo)。
例如,我们对于以下模型:
$$ \displaylines { W & \sim & Binomial(9, p) \\ p & \sim & Normal(0.5, 0.1) } $$
可以使用 MCMC 方法来学习 $p$ 的值,使用 rethinking 包如下:
ulam(
alist(
W ~ dbinom(W + L, p), # binomial likelihood
p ~ dnorm(0.5, 0.1) # uniform prior
),
data = list(W = 6, L = 3)
)
功能上相当于:
W <- 6
L <- 3
# MCMC 的一个 chain
n_samples <- 1000
p <- rep(NA, n_samples)
# prior
p[1] <- rnorm(1, 0.5, 0.1)
for (i in 2:n_samples) {
# 选取一个新的 p
p_new <- rnorm(1, p[i - 1], 0.1)
# 比较新旧 p 的结果
q0 <- dbinom(W, W + L, p[i - 1])
q1 <- dbinom(W, W + L, p_new)
# 判断是否接受新的 p
p[i] <- ifelse(runif(1) < q1 / q0, p_new, p[i - 1])
}