tak0kadaの何でもノート

発声練習、生存確認用。

医学関連は 医学ノート

「Probabilistic Programming and Bayesian Methods for Hackers」を読んだ - (5章)

第5章は損失関数について。損失関数の計算に真の値を使わずにどう計算するのか気になっていたが事後分布を使うと知って納得。

損失関数

損失関数は予測した分布がどれくらい悪いのかを評価する関数。計算に便利で導入されたらしいが、コンピュータがあるので今使われる理由は「robust to application」だかららしい。よく使われるような有名なものを以下に書いた。

$$ L(\theta, \hat{\theta}) = \begin{cases} &(\theta - \hat{\theta})^{2} &: &\text{平方損失}\\ &|\theta - \hat{\theta}| &: &\text{絶対損失}\\ &1_{\hat{\theta} \neq \theta} &: &\text{0-1損失}\\ &-\hat{\theta}log(\theta) - (1-\hat{\theta})log(1-\theta) &: &\text{log損失 } (\theta, \hat{\theta} \in [0,1]) \end{cases} $$ 平方損失は線形回帰に使われる。0/1損失は分類アルゴリズム、log損失は期外学習に使われるらしい。

この章の例もそうだがこれら以外で自分で簡単に定義できるので他にも考えることができて、 \frac{|\theta - \hat{\theta}|}{\theta(1-\theta)} 1 - e^{-(\theta - \hat{\theta})^{2}}などとすることもできる。

頻度主義の場合は L(\theta, \hat{\theta}) \thetaに推定値を代入して使うと思われる。ベイズ主義では \thetaは予測された事後分布になり、 \frac{1}{N}\sum L(\theta_{i}, \hat{\theta})を計算して代用する。

例1 「The Price is Right」

  • 「The Price is Right」というテレビ番組は2人の出演者が商品の値段を予測比べをして、勝てばその商品がもらえる番組らしい。ただし予測が実際の値段を超えず、250以上下回っていない場合のみはいけない。

  • 事後分布の計算

この例では価格の事前分布としてこれまでの番組での価格分布を正規分布にして用いる。そしてここからサンプリングして出てきた結果を元に事後分布を計算するのがいつもの流れだが、今回はまだ価格を知ってはおらず出演者が予測した価格分布しか情報がない。そこで事前分布の平均と分散の逆数を \mu τとして価格がxになる確率を \sqrt{\frac{τ}{2\pi}} exp(-\frac{τ}{2} (x-\mu)^{2})として事後分布を計算する。

ここで分布を修正するときに@pymc.potentialを使う。@pymc.potentialは出来上がったモデルに特に親子関係がない条件を付け加えたいときに使われるデコレータで、potentialになった変数はpymc.modelに付け加える必要がない。

@pm.potential
def error(true_price, ...):

などとするといい。

f:id:kuyata:20140823173748p:plain

黒い曲線が元の分布で赤色の分布が事後分布。

  • 損失関数の計算
import scipy.optimize as sop

def showdown_loss(guess, true_price, risk=80000):
    loss = np.zeros_like(true_price)
    loss[guess > true_price] = risk
    ix = [(guess <= true_price) * (guess > true_price - 250)]
    loss[ix] = -2 * np.abs(true_price[ix])
    ix = [guess <= true_price - 250]
    loss[ix] = np.abs(true_price - guess - 250)

expected_loss = lambda guess, risk: shutdown_loss(guess, mcmc.trace("true_price")[:], risk)
for _p in risks:
...
    min_results = sop.fmin(expected_loss, 15000, args=(_p,), disp=False)

scipy.optimize.fminは関数の最小値を探してくれる。

f:id:kuyata:20140823204524p:plain

損失関数が最小なのは事後分布の最大値の20000前後からかなり小さくなっている。

例2: 金利の推測

$$ R = \alpha + \beta x + \epsilon $$ というモデルについて考える。  \alpha \betaは平均0、精度0.0001の正規分布 \epsilonには一様分布なstdの2乗の逆数を使う。

import pymc as pm
from pymc.Matplot import plot as mcplot

std = pm.Uniform("std", 0, 100, trace=False)  # this needs to be explained.


@pm.deterministic
def prec(U=std):
    return 1.0 / (U) ** 2

beta = pm.Normal("beta", 0, 0.0001)
alpha = pm.Normal("alpha", 0, 0.0001)


@pm.deterministic
def mean(X=X, alpha=alpha, beta=beta):
    return alpha + beta * X

obs = pm.Normal("obs", mean, prec, value=Y, observed=True)
mcmc = pm.MCMC([obs, beta, alpha, std, prec])

mcmc.sample(100000, 80000)
mcplot(mcmc)

収束していたらOK。

損失関数は飽きたのでパス。

例3: ダークマターによるハロー探し

TODO