2017年7月11日 星期二

[貝氏] Paper digest (4) 煩死人的Variational Bayes續集 -- Blackbox Variational Inference

這篇接著很久很久寫的煩死人的 Variational Bayes 初探往下寫的。如果用食記部落客的語法,應該改成「再訪!煩死人的Variational Bayes」(超無聊)。

好,會寫這篇的原因是因為最近拜讀了一篇由大神David Blei團隊所寫的這篇文章,順便邊讀邊寫,吸收快又好。題目叫做Blackbox Variational Inference,你沒看錯Variaional Bayes也有黑箱版的,這篇文章刊出的時間是2014年,那年台灣高中生也剛好在反黑箱課綱,真的蠻潮的。

這個方法的賣點是不需要手動計算複雜的積分也可以做Variational Inference。



先複習一下,Variational Bayes的精神就是找一個替代的替身 $q(\theta)$ 並且讓它和posterior $p(\theta, x)$ 越像越好,也就是盡全力把 $KL[q(\theta), p(\theta, x)]$ 變得很小就對了!接下來,

$KL \left[q \left( \theta \right),p \left( \theta \right|x) \right] $

$=\int q \left( \theta \right) \log \frac{q \left( \theta \right)}{p \left( \theta,x \right)} d \theta- \int q \left( \theta \right) \log p \left(x\right) d\theta$

$=\int q\left(\theta\right)\log\frac{q\left(\theta\right)}{p\left(\theta,x\right)} d\theta-\log p\left(x\right)$

$=E_{q}[q(\theta)] - E_{q}[\log p(\theta, x)]-C$

上式的$ E_{q}[q(\theta)] - E_{q}[\log p(\theta, x)]$取負號以後叫做 ELBO (Evidence lower bound),也就是

$ ELBO = E_{q}[\log p(\theta, x)]-E_{q}[q(\theta)]$

只要不斷讓ELBO越來越大,  $KL[q(\theta), p(\theta, x)]$ 就會越來越小。

好現在假設我們的其中一個替身叫做$q(\theta|\lambda)$,最佳化 $\lambda$ 的梯度(gradient)就是

$\nabla_{\lambda}\int (\log p(\theta, x)-\log q(\theta|\lambda))q(\theta|\lambda)d\theta$

$=\int \nabla_{\lambda}(\log p(\theta, x)-\log q(\theta|\lambda))q(\theta|\lambda)d\theta$

$+\int \nabla_{\lambda}q(\theta|\lambda)(\log p(\theta, x)-\log q(\theta|\lambda))d\theta$

其中,

$\int \nabla_{\lambda}(\log p(\theta, x)-\log q(\theta|\lambda))q(\theta|\lambda)d\theta$

$=-E_{q}[\nabla_{\lambda}\log q(\theta|\lambda)]=0$

剩下另外一個,因為

$\nabla_{\lambda}q(\theta|\lambda)=q(\theta|\lambda) \nabla_{\lambda}\log q(\theta|\lambda)$

就可以寫成

$\int \nabla_{\lambda}\log q(\theta|\lambda)(\log p(\theta, x)-\log q(\theta|\lambda))q(\theta|\lambda)d\theta$

$=E_{q}[ \nabla_{\lambda}\log q(\theta|\lambda)(\log p(\theta, x)-\log q(\theta|\lambda))]$

這個東西是可以用Monte Carlo integration估計的,只要從 $q$ 中抽樣就可以了。

因此說了一堆,黑箱版本的好處其實就是不需要手動計算複雜的積分(再次強調)也可以找出梯度,然後一次做最佳化就可以了。

2017年3月3日 星期五

[Scala] Big Data(6) submit spark job

這篇是這篇(默默改版了)的Spark版,就這樣而已ㄏㄏ。

冰島,隨便一拍都可以當啤酒廣告。沒錯,我在炫耀。


劇情設定是這樣的,假設我有三個檔案在hdfs上,分別是temp/input_1.txt, temp/input_2.txt和 temp/input_3.txt,各自格式都不一樣,然後我想要計算各科的平均分數。
$ hdfs dfs -cat temp/input_1.txt
WUJ-360100;math;56
WPY-802007;math;98
FKT-670008;science;67
$ hdfs dfs -cat temp/input_2.txt
{Number:FJB-004150, Subject:math, Score:96}
{Number:QDG-300700, Subject:chinese, Score:90}
{Number:JVY-030140, Subject:chinese, Score:71}
$ hdfs dfs -cat temp/input_3.txt
[Number=>ITM-501806; Subject=>science; Score=>82]
[Number=>QBE-003981; Subject=>math; Score=>85]
[Number=>EUJ-017009; Subject=>chinese; Score=>63]

相較於Hadoop的JAVA file總是要寫得的叨叨噓噓,Spark明顯親民多了,根本就不用什麼Multipleinputs啊啊啊很棒!所有的程式碼只有這樣:

import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf
import org.apache.hadoop.fs.FileSystem

object MultiInput {
  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("Multiple Input Example")
    val hadoopConf = new org.apache.hadoop.conf.Configuration()
    val fs = org.apache.hadoop.fs.FileSystem.get(hadoopConf)

    val inPath1 = new org.apache.hadoop.fs.Path(args(0))
    val inPath2 = new org.apache.hadoop.fs.Path(args(1))
    val inPath3 = new org.apache.hadoop.fs.Path(args(2))
    val outPath = new org.apache.hadoop.fs.Path(args(3))

    if(fs.exists(outPath)){
        fs.delete(outPath)
    }

    val sc = new SparkContext(conf)
    val file1 = sc.textFile(inPath1.toString)
    var rdd1 = file1.map(line => (line.split(";")(1), line.split(";")(2)))

    val file2 = sc.textFile(inPath2.toString)
    var rdd2 = file2.filter(_.contains(",")).map(s => (
        s.split(",")(1).split(":")(1), 
        s.split(",")(2).split(":")(1).replace("}", "")))

    val file3 = sc.textFile(inPath3.toString)
    var rdd3 = file3.map(s => (
        s.split(";")(1).split("=>")(1), 
        s.split(";")(2).split("=>")(1).replace("]", "")))

    val rdd = rdd1.union(rdd2).union(rdd3)

    val res = rdd.combineByKey(
        (x: String) => (x.toInt, 1),
        (acc:(Int, Int), x) => (acc._1.toInt + x.toInt, acc._2.toInt + 1),
        (acc1:(Int, Int), acc2:(Int, Int)) => (
            acc1._1.toInt + acc2._1.toInt, 
            acc1._2.toInt + acc2._2.toInt)
        ).map(k => (k._1, k._2._1.toDouble / k._2._2.toDouble))

    res.saveAsTextFile(outPath.toString)
    
    }
}

然後把以上程式碼存成一個叫做MultiInput.scala的檔案。

之後進入打包流程,就比較麻煩了。
首先先建立一個打包需要的資料夾,這裡就姑且叫做multiInput吧!
$ mkdir ./multiInput
$ mkdir -p ./multiInput/src/main/scala
然後把剛剛的寫好的那的scala檔案丟到/src/main/scala目錄下
$ mv MultiInput.scala ./multiInput/src/main/scala/MultiInput.scala
創建一個叫做multiInput.sbt的檔案(極重要!)
$ vim ./multiInput/simple.sbt
內容如下:
$ name := "Multiple Input"

version := "1.0"

scalaVersion := "2.10.5"

libraryDependencies += "org.apache.spark" %% "spark-core" % "1.6.0"
然後進到資料夾multiInput進行一個打包的動作(要先安裝好sbt喔)
$ cd multiInput
$ sbt package
成功打包以後,會在target/scala-2.10底下搞到一個打包好的.jar檔案
$ ls target/scala-2.10/
classes  multiple-input_2.10-1.0.jar
submit spark job的方法如下
$ spark-submit --class "MultiInput" target/scala-2.10/multiple-input_2.10-1.0.jar \ 
temp/input_1.txt temp/input_2.txt temp/input_3.txt temp/output_mp
路徑記得要打對!路徑記得要打對!路徑記得要打對!很重要!

跑完之後就可以到hdfs上看結果了
$ hdfs dfs -getmerge temp/output_mp sp_test
$ cat sp_test
(math,83.75)
(chinese,74.66666666666667)
(science,74.5)

2017年2月25日 星期六

[Scala] Big Data(5) 雜記,Cloudera Quickstart VM和萬年word count

其實蠻久之前就有用過Spark這個東西了,只是最近再拿出來玩玩發現發現好多東西都忘記,忘得精光那種,筆記這種東西真的好重要啊啊啊啊啊。

Cloudera Quickstart VM


為了練習Spark自己搞一個server雖然很霸氣,但不是所有人都有錢有閒這樣做的,如果只是為了練習,或是用少量資料驗證一下想法可不可行,誠心建議使用Cloudera Quickstart VM就好了。這個東西真的超級佛心的,一包拿來裡面該有的都有(Hadoop, Spark, Hive...),然後設定也算簡單,尤其是對於我這種對Architecture很沒轍的技術廢物(無誤)來說。

題外話,中視《飢餓遊戲》好看!
喔對了,為了平衡報導,其實另外一家叫做Hortonworks提供的Sandbox也不錯,有興趣的人也可以試試看。

然後我選用Docker VM,因為設定超級無敵簡單的就一頁而已,指令也沒幾行,連我都搞得定簡直太棒!不過得先安裝Docker就是了。設定步驟很簡單,以下也不過是把網頁上的Instruction翻成中文而已就醬。

在安裝好Docker之後,就打開terminal,用docker pull指令開始下載Cloudera QuickstartVM。
$ docker pull cloudera/quickstart

整包東西大概4GB左右,要稍微等一下。

然後鍵入指令,裡就會發現有一個image叫做cloudera/quickstart耶!(訝異個屁)
$ docker images
EPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
cloudera/quickstart  latest              4239cd2958c6        10 months ago       6.34 GB

記下對應的IMAGE ID,以上圖為例也就是4239cd2958c6,用來啟動Docker VM囉!
$ docker run \
--hostname=quickstart.cloudera \
--privileged=true \
-t -i -p 8888 \
[IMAGE ID] /usr/bin/docker-quickstart

然後那個[IMAGE ID]記得要換一下。然後基本上經過一段時間的等在就可以成功進入VM的根目錄了,我啟動的時候hue沒有成功,但是在Docker VM開始run之後重複幾次restart神奇的事情就發生了,像這樣:
[root@quickstart /]# service hue restart
Shutting down hue:
Starting hue:                                              [  OK  ]

但如果不是很在意hue的話也可以不理它啦,反正天下事只要牽涉到UI就是神煩(翻白眼)。至於確切原因我也不知到為何,反正它就是好了,很煩(知道原因的拜託留言或是托夢告訴我拜託!)。

看到Hue web UI就是心曠神怡而已

然後注意,如果這時候關掉terminal的話,所有資料都會消失,如果不想資料消失的話,請在剛剛的啟動加上-p選項或者用ctrl+p -> ctrl+q關掉terminal,這樣VM就會繼續運行。如果要重新接上,請用docker ps找到對應的conatiner id
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED    
56703ef28dc3        4239cd2958c6        "/usr/bin/docker-q..."   2 hours ago

然後docker attach
$ docker attach [CONTAINER ID]

如果要在執行其他指令的話,可以用docker exec,概念上和ssh差不多
$ sudo docker exec -i -t [CONTAINER ID] /bin/bash

千篇一律的Word count problem


接下來就是用Spark跑跑看最白爛(對,即便就是白爛我還是要跑)的word count,就是計算字數啦。首先得把檔案用docker cp從本機丟過去docker VM的container裡面。
$ docker cp word_count.txt [CONTAINER ID]:/word_count.txt

然後進入docker VM,把這個剛剛丟過來的檔案推到HDFS上。
[root@quickstart /]# hdfs dfs -mkdir temp
[root@quickstart /]# hdfs dfs -put word_count.txt temp/word_count.txt

之後進入Spark shell
[root@quickstart /]# spark-shell

之後就開始跑罐頭程式
scala> val file = sc.textFile("temp/word_count.txt")
file: org.apache.spark.rdd.RDD[String] = temp/word_count.txt MapPartitionsRDD[1] at textFile at :27

scala> val counts = file.flatMap(line => line.split(" ")).map(word => (word, 1)).reduceByKey(_ + _)
counts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[4] at reduceByKey at :29

scala> counts.collect().foreach(println)
(Groovy..,1)
(found,1)
(Check,1)...

scala> counts.saveAsTextFile("temp/output")

寫資料路徑的時候要稍微小心一點,其實不一定像網路上的demo一樣寫完整的路徑,像這樣。

scala> val file = sc.textFile("hdfs://quickstart.cloudera:8020/user/root/temp/word_count.txt")

然後看一下HDFS看看有沒有存成功
[root@quickstart /]# hdfs dfs -ls temp/output
Found 3 items
-rw-r--r--   1 root supergroup          0 2017-02-25 19:56 temp/output/_SUCCESS
-rw-r--r--   1 root supergroup         93 2017-02-25 19:56 temp/output/part-00000
-rw-r--r--   1 root supergroup        127 2017-02-25 19:56 temp/output/part-00001


2016年8月29日 星期一

[貝氏] 有關ABC的一些筆記

ABC是Approximate Bayesian Computation的縮寫,名字真的還蠻俏皮的。由於實習的關係,目前為止已經被迫和這個東西相處了三個月,寫一篇筆記 。

與本文無關,純粹覺得好笑


基本上,貝氏統計基本上可以濃縮下面成一行:

$\pi(\theta|x)\propto\pi(\theta)p(y|\theta)$

$\pi(\theta|x)$是所謂的後驗分配(posterior distribution),基本上是得用手算的,但通常來說不太可能,尤其是模型非常複雜的時候,於是就出現了MCMC (Monte-Carlo Markov chain)還有Variational Bayes之類的方法,讓大家日子在電腦的方著之下可以好過一點(應該說很多)。

但隨著大家的胃口越來越大,像是是在處理基因或是疾病散播問題時,很多時候模型已經複雜到連概似函數(likelihood function) $p(y|\theta)$ 都寫不出來。ABC就是為了這樣的情境而出現的。

Rejection sampling ABC


這是一個最基本的ABC演算法,假設我們有一個simulator $S$,基本上可以把$S$想成一個由參數空間 $\Theta$ 投射到資料空間 $Y$ 的函數$S: \Theta \rightarrow Y$,如果Simulator $S$裡有潛在變數$v$的話simulator則寫成,$S: \Theta \times V \rightarrow Y$

若是手上所收集到的資料是 $y_{0}$ ,而先驗分配prior是 $\pi(.)$ ,演算法的步驟如下

for $i=1$ to $N$ do
    repeat
        從 $\pi(.)$ 抽出$\theta$
        由 $S(\theta)$ 產生 $y_{\theta}$
    until $d(y_{0}, y_{\theta})<\epsilon$
    $\theta^{(i)} \leftarrow \theta$
 end for

 $d: Y \times Y \rightarrow \mathbb{R}$ 是一個距離函數,用來定義生成的 $y_{\theta}$ 和觀察到的 $y_{0}$ 兩筆資料的異同。這個函數可以是Mean square error或是其他特定的函數,而$\epsilon$則是一個很小的容許值。值得注意的是,演算法中完全不需要定義所謂的likelihood函數。

由於likelihood函數的功能在上述的演算法中已經被$d$ 函數所取代,所以如何定義一個好的$d$在ABC中就是一個非常重要的課題了。

普遍來說,直接比較兩筆資料很沒效率,所以一般而言會比較統計量,summary statistics $s_{obs}$ 和$s_{simulated}$,而理論上,如果所選取的$s$是充分統計量(sufficient statistics)的話,$p(\theta|y_{obs}) = p(\theta|s_{obs})$。而統計量的選曲又是一個很大的題目了,這裡先跳過哈哈哈哈。


MCMC-ABC


Rejection sampling是一個很直覺的做法,但是收斂速度往往很慢,因此MCMC-ABC之類方法就發展起來彌補其不足。

Metropolis-Hastings sampler

Metropolis-Hastings sampler [1] (以下簡稱MH)對熟悉貝氏統計的人應該都不算陌生,在進行MH的時候,必須要選定一個proposal distribution $q(.|\theta)$ 用以決定參數在抽樣時移動的行為。

設定起始值$\theta^{(0)}$

for $t=1$ to $N$ do
    從 $q(.|\theta^{(t-1)})$ 抽出$\theta$
    計算 $a = \frac{\pi(\theta) p(y|\theta) q(\theta^{(t-1)}|\theta)}{\pi(\theta^{(t-1)}) p(y|\theta^{(t-1)}) q(\theta|\theta^{(t-1)})}$
    抽出 $u \sim Uniform(0, 1)$
    if $u < a$ then
        $\theta^{(t)} \leftarrow \theta$
    end if
    $\theta^{(t)} \leftarrow \theta^{(t-1)}$
end for

MCMC-ABC


MCMC-ABC [2]等於模仿了MH只是用rejection sampling中比較生成資料的概念取代了需要概似函數的部分

for $t=1$ to $N$ do
    從 $q(.|\theta^{(t-1)})$ 抽出$\theta$
    由 $S(\theta)$ 產生 $y_{\theta}$
    if $d(y_{0}, y_{\theta})<\epsilon$ then
        計算 $a = \frac{\pi(\theta) q(\theta^{(t-1)}|\theta)}{\pi(\theta^{(t-1)}) q(\theta|\theta^{(t-1)})}$
        抽出 $u \sim Uniform(0, 1)$
        if $u < a$ then
            $\theta^{(t)} \leftarrow \theta$
        end if
    end if
    $\theta^{(t)} \leftarrow \theta^{(t-1)}$
end for

搞了半天其實說穿了也沒什麼,呵呵。當然還有很多好事之徒發展了很多變形,這裡就不討論了。


提升效率


因為Simulator通常很複雜,也是最耗時的步驟,所以也有一些方法發展出來減少跑Simulator的次數以增進效率。這裡介紹Regression adjustment和BOLFI

Regression adjustment


一般來說,$\epsilon$是越小越好,最好可以接近零。但是如果真的設定$\epsilon = 0$的話又很花時間,因為會製造成堆沒路用的simulated data。

因此,與其這樣,不如直接統計建模,描述探討$\theta$和summery statistics $s$的關係。

$\theta^{i}=m(s^{i})+e^{i}$

其中$e^{i}$是error term。Beaumont [3]等人提出的方法是用一個簡單的線性回歸建模,

$m(s^{i})=\alpha + \beta^{T} s^{i}$

因此,在建模完成之後,就可以利用該模型回推回去若當 $s^{i} = s_{obs}$ 時, $\theta$ 會在哪裡,意即:

$\theta^{*i} = m(s_{obs})+(e^{i})$

而根據模型,可以估計$e^{i}$

$e^{i} = \theta^{i}-\hat{m}(s^{i})$

我們可以回推

$\theta^{*i}=\hat{m}(s_{obs}) + (\theta^{i} - \hat{m}(s^{i}))$

當然,市面上也有其他更複雜的模型用來描述 $\theta$ 和 $s$ 的關係,這裡就不詳述了。

BOLFI


這個東西的全稱是叫做Bayesian Optimization for Likelihood-Free Inference of Simulator-Based Statistical Method [4]。個人目前不是很喜歡這個東西,但似乎大家都在用,所以稍微提一下(?)

其實就是使用Gaussian Process Optimisation的技巧,去針對$\theta$和$d(y_{\theta}, y_{0})$的關係進行Gaussian process建模,並進行最佳化。

並且,在某些條件下,概似函數(likelihood)是可以由中央極限定理或是無母數的方法估計的,所以BOLFI也提供了一個直接由$\theta$取得likelihood value的架構。


[1] Chib, Siddhartha, and Edward Greenberg. "Understanding the metropolis-hastings algorithm." The american statistician 49.4 (1995): 327-335.
[2] Marjoram, Paul, et al. "Markov chain Monte Carlo without likelihoods."Proceedings of the National Academy of Sciences 100.26 (2003): 15324-15328.
[3] Beaumont, Mark A., Wenyang Zhang, and David J. Balding. "Approximate Bayesian computation in population genetics." Genetics 162.4 (2002): 2025-2035.
[4] Gutmann, Michael U., and Jukka Corander. "Bayesian optimization for likelihood-free inference of simulator-based statistical models." arXiv preprint arXiv:1501.03291 (2015).


2016年5月29日 星期日

[機器學習] Paper digest (3) Computational rationality: A converging paradigm for intelligence in brains, minds, and machines

原文連結在這裡,一篇登在Science上的review。好久沒寫blog,發現中文整個退化到不行,連帶我原本就不好的英文,真的要變文盲了。

先來個風景照(芬蘭・坦佩雷)



這篇回顧了computational rationality在人工智慧,認知科學及神經科學上的發展。

先稍微整理一下所謂computational rationality:

首先,最終的desicion必須要有最大的expected utility,這樣的概念首先由von Neumann等人[1]提出,即所謂的MEU(maximize expected utility) principle。至於為什麼是expected utility呢?原因是因為我們所身處的世界充滿了不確定性(uncertainty),也就是凡事皆機率的意思,因此需引入期望值(expected value)的概念。

通常現實世界所處理的問題都頗複雜或是大尺度的(large scale),因此在計算expected utility時,就經常需要動用逼近(appriximation)等計算技巧。

而appriximation本身也是決策的一環,因為計算需花上可觀的時間及資源,而這也是computational rationality的核心。在最大化expected utility的同時也要將計算所可投注有限資源及時間納入考慮。

至於computational rationality的模型則是建立於:

1. Infernece under uncertainty.

2. The feasibility and implications of actions.

3. Bounded computation power.

4. Multilevel, or multireasoning.


人工智慧

IBM Watson參加電視益智節目時,基本上Watson的計算時間(時間內要作答)和計算能力是被限制的,因此Watson基本上並沒有辦法『想』或是『窮舉』出所謂『完美無誤』的答案,而是要在『有限的時間及資源』下『猜』出『近乎完美』或『正確機率較高』的答案。

當然AI領域還有其他例子,像是Google自動駕駛汽車或是,Microsoft的個人秘書。


認知科學

心理學家發現,人類並非所謂「直覺的統計學家」(intuitive statisticians)。很多時候,人類的決策和所謂的「最佳決策」往往天差地遠。

Computational rationality可以提供一個架構來解釋這種現象。當腦在缺乏足夠資源的情況下被迫要做出決定時,所謂充滿缺陷的決策就會出現,但這些看似非理性的決策很有可能是考量了當下的計算資源所做出最理性的決策(哇勒好玄)。

文中提到抽樣貝氏推論(approximating Bayesian inference by sampling),可以作為一個例子。基本上,所抽的樣本越多,所得到關於後驗機率分配(posterior distrubution)的資訊就越正確,但在時間及計算能力的限制下,往往只能得到一小部分的樣本,因此讓決策產生偏誤,計算生物學界就有學者此利用抽樣演算法作為模擬神經迴路的行為[2](看到嚇了一跳,有一種這樣也可以的感覺)。

神經科學

Computational rationality可以解釋分別屬於腦中不同的核區(cortex)的兩個系統:model-based system和model-free system的分工。

一般認為,model-based system較依賴經驗,需要較長時間(速度較慢),卻比model-free system來得有彈性。在剛開始的學習階段,因為model-free system所做出的決策往往較不精準,model-based system通常有較好的效果而被採用。但經過一定時間的學習,model-free system的決策也可以優化到一定程度,這時model-based system反而會被放棄採用。

然而,學界也證實了大腦再選取兩者時,計算的消耗也被考慮在內[3][4]。


未來發展

文末,作者提到computational rationality是一個很有潛力的架構,並且應可以應用在更多不同的領域。然而更進一步的理論架構,以及更多的證實,或甚至是辯論都是學界可以繼續努力的方向。


[1] Von Neumann, J., & Morgenstern, O. (2007). Theory of games and economic behavior. Princeton university press.

[2] Buesing, L., Bill, J., Nessler, B., & Maass, W. (2011). Neural dynamics as sampling: a model for stochastic computation in recurrent networks of spiking neurons. PLoS Comput Biol7(11), e1002211.

[3] Daw, N. D., Gershman, S. J., Seymour, B., Dayan, P., & Dolan, R. J. (2011). Model-based influences on humans' choices and striatal prediction errors.Neuron69(6), 1204-1215.

[4] Keramati, M., Dezfouli, A., & Piray, P. (2011). Speed/accuracy trade-off between the habitual and the goal-directed processes. PLoS Comput Biol7(5), e1002055.

2016年2月21日 星期日

[貝氏] Paper digest(2) Slice sampling

最近啃了大師級學者Neal發表在Annals of Statistics上的這篇原著,十多年前的東西了。殿堂級的期刊果然很難讓人親近啊,有夠多頁,光是讀完都很很令人吐血。

有別於Gibbs sampling和MH sampling, slice sampling屬於Auxiliary sampling的範疇,除了抽出posterior distribution的樣本,更額外抽出另一個輔助性的,domain不一樣的樣本,歐好像有點玄。

總之先來看抽樣步驟:
1)選擇一個 starting point $x_{0}$ 並注意$f(x_{0})$ 必須大於$0$ ,並產生一個 $Uniform\ distribution\ U(0,\ f(x_{0}))$,也就是圖上的綠線


2)由 $U(0,\ f(x_{0}))$ 抽出一個 auxiliary variable $y_{0}$並產生一集合 $X^{*} = \{x:\ f(x)\geq y\}$,也就是圖上的紅色實線。這個動作叫做切割,也就是slice


3)由上一步驟產生的集合 $X^{*}$ 中,均勻(uniformly)抽出下一個 $x_{1}$ ,也就是紅點對用回x軸的位置並回到步驟二



換句話說,擁有越高posterior density的樣本,在每次切割(slice)的時候就越有機會被抽到,如此一來抽樣的結果就會收斂到Posterior distribution

2015年9月25日 星期五

[無母] Kernel Density Estimation

很久以前就看過這個方法,但都沒有仔細研究過。

有許多方法可以用來估計機率分配,以前課本上教的就是先假設一個機率分配(常常是Normal),然後用動差法(moment-method)或者是最大概似估計(most likelihood)把參數找到後帶入。

無母數的做法就比較不一樣,在操作的時候避免假設一個太硬性的框架,以期發現更多數據底層的結構,KDE (Kernel Density Estimation)就是其中之一。話說回來,其實Histogram就是一種無母數的機率分配估計方法,像是下圖:


其實就是在計算
$p_{x}=\frac{\#of \ x_{i}\ is\ in\ the\ same\ bin\ with x}{bin\ width}$

所使用的參數就是bin的寬度和起始值(如上圖就是0)。

KDE也是類似的概念,要回答的問題是,當某個$x$並未被觀察到的時候,究竟背後的機率是多少?KDE回答問題的方式,就是去看$x$相進的點出現的情形,如果出現的多,表示其實$x$出現的機率很高,只是剛好by chance沒有被觀察到而已,反之則$x$本身出現的機率就是低的。

所以,當$x$出現機率的估計值就是

$p(x)=\frac{1}{nh}\sum_{i}kernel\left (\frac{x-x_{i}}{h}  \right )$

$h$是所謂的帶寬,$kernel$一般而言是以零為中心對稱的函數,並且所有值域的積分必須是$1$,像是Gaussian function

$k(u)=\frac{1}{\sqrt{2\pi}}\exp(\frac{u^{2}}{2})$

以下是我用不同$h$就產生上圖(Hitogram)的資料做的擬和





可以看出$h$的選擇很重要,太大的帶寬會導致under-fitting,太小的則導致over-fitting。帶寬的選擇又是另外一個很大的題目了。