使ってみよう〜BUGS(乱数を使ってベイズ推定)〜R+openBUGS
- ここ数日のR+opeBUGSの使用歴を散逸しないようにepub化
- 以下はRmdファイルです。こちらなどを参考にすれば、自由にhtml文書化・epub化できます(が、それが面倒な場合には、kindleで)
- 近くこちらから
使ってみよう?BUGS(乱数を使ってベイズ推定)?R+openBUGS
- 作者: ryamada
- 発売日: 2014/03/28
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
- 主な内容は
# 使ってみよう〜BUGS(乱数を使ってベイズ推定)〜R+openBUGS ## BUGSとは BUGSはBayesian inference Using Gibbs Samplingの略である。 ベイズ推定をするときには次のようなものを使う。 事前分布、データ、事後分布、それらをつなぐ関数など。 つなぐ関数などをごちゃごちゃと書くのは大変なので、モデルとして、事前分布の関数、事後分布の関数、乱雑項の関数などを書いておいて、後は、乱数を発生させ、必要に応じて適切な分布に沿った乱数を使うためにGibbsサンプリングをするという手法である。 openBUGSはそのようなBUGSを支えるオープンソースであり、RはそのopenBUGSを呼び出して実行する。 ## 準備:openBUGSを使えるようにする openBUGSのダウンロードとインストールをする。ダウンロード先はhttp://www.openbugs.net/w/Downloads ## RからopenBUGSを使えるようにする ```{r,warning=FALSE} install.packages(c("BRugs", "coda", "R2WinBUGS","Rcpp")) library(R2WinBUGS) library(BRugs) ``` ## 試しに使ってみる 必要なものは、 * Rの実行コマンドと * Rが読み込むBUGS用のモデルファイル まずは一次線形回帰に使ってみる ### 非BUGS推定 BUGSを実行する前に、BUGSでない手法での推定をしてみる。 ```{r} # 適当にデータを作る # 要素数 N <- 100 # 説明変数xは適当な範囲の一様乱数 x.mean <- 3 x.sd <- 1 x <- rnorm(N,x.mean,x.sd) # 乱雑項 v <- 1 z <- rnorm(N,0,sqrt(v)) # 従属変数yはxの一次線形の値に乱雑項を加えたもの beta1 <- 2 beta2 <- 4 y <- beta1 + beta2*x + z # そのデータを見てみて、lm()で回帰して回帰直線を引きます # 乱雑項zがxに依存しているので、このような回帰は「正しく」ないけれど、そんなことは知らなかったとして回帰する lm1 <- lm(y ~ x) # その結果 summary(lm1) ``` $$ y = \beta_1 \times x + \beta_2 $$ のbeta1,beta2 の値がそこそこの精度で推定されていることが、summary(lm1)のCoefficientsのEstimateの出力(Intercept),xとでわかる。 ```{r} # プロット plot(x,y,pch=20) abline(lm1, col="blue", lwd=2) ``` ### BUGS推定 さて、これをBUGSでやってみる。 #### モデルとモデルファイル BUGSするには、モデルが必要。 モデルはテキストファイルに書いて、Rから読み込ませる。 モデルファイルの意味や、その後に続くRの細かいことは、ひとまず置いて、実行ができるかどうかを確かめるために実施してみよう。 ```{} model { for (i in 1:N) { y[i] ~ dnorm(mu[i], S) mu[i] <- beta1 + beta2 * x[i] } beta1 ~ dnorm(0, 0.0001) beta2 ~ dnorm(0, 0.0001) S ~ dgamma(0.0001,0.0001) } ``` この内容を"lm1.txt"という名前でRのワーキングディレクトリに保存しておけばよい。 同様のファイルをRの中から作成するには次のようにする。 ```{r} lm1model <- function(){ for(i in 1:N) { y[i] ~ dnorm(mu[i], S) mu[i] <- beta1 + beta2 * x[i] } beta1 ~ dnorm(0, 0.0001) beta2 ~ dnorm(0, 0.0001) S ~ dgamma(0.0001, 0.0001) } file.name <- "lm1.txt" write.model(lm1model,file.name) ``` また、MCMCでの実行をするために、推定したいパラメタの初期値を与える必要がある。 beta1,beta2には事前予想値である0を与えればよいだろうし、Sについては、適当に正の値(ここでは1)を与えればよい。 実際にBUGSをRで実行するにはbugs()関数に、しかるべきルールでデータと初期値とモデルファイルのパスとopenBUGSプログラムのパスを与えるとともに、MCMCの実行条件を与える必要がある。 そのコマンドは以下のとおりである。 ```{r,warning=FALSE,message=FALSE} # データはリストで与える。y~xの回帰のためには説明変数、従属変数、データ数を与える data1 <- list(y=y, x=x, N=N) # 初期値の指定 in1 <- list(beta1=0,beta2=0, S=1) inits <- list(in1) # 初期値は入れ子になったリストになる inits # 推定パラメタの名前 param <- c("beta1","beta2","S") # テキストファイルでBUGS用のモデルを記載 model1 <- file.name # 実行 # model1に指定したファイルのパスはもちろんRの実行ディレクトリに合わせる。Rで書きだせば、ワーキングディレクトリに作られているはず # bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323"という指定はopenBUGSを動かすための指定なので、インストールした先のディレクトリの名前を確認しておく。以下のパスは、2014/03/26にダウンロードしたopenBUGSのデフォルトディレクトリ # MCMCなので、初期値依存の部分burnin部分(n.burnin)とそれ以降を含めた全繰り返し処理数n.iterとを指定してある。 bugs1 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=300, n.burnin=100, n.thin=2, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") ``` 実行条件と結果とを表示する。 プロットもしてみる。 興味があるのは各推定パラメタの平均値や中央値、それに区間推定値であるからそれらが示されている。 ```{r} print(bugs1) plot(bugs1) ``` bugs()関数の出力の平均・標準偏差・クオンタイル値(0.1,0.5,0.9)を取り出して、桁数を増やして表示してみる。 ```{r} # 出力bugs1オブジェクトから、結果行列を取り出してpost1オブジェクトとする post1 <- bugs1$sims.matrix # post1の各列にパラメタとして採択された値が格納されているのでそれらの記述統計を取る apply(post1,2,mean) apply(post1,2,sd) apply(post1,2,quantile,c(0,1,0.5,0.9)) ``` $$ y = beta1 + beta2 x$$ の係数推定がそれなりに良いことがわかる burnin 後の記録として残っている部分の推移を示す。 値が大きくなったり小さくなったりするので、じゃみじゃみするが、全体の傾向としては、上下に幅がある状態で安定(水平)になっていることがわかる。 水平方向に安定していれば、推定がうまく行っていると考える。 本当はn.iterを増やして、確かに水平方向に安定していることを確かめる方が良い。 ```{r} par(mfrow=c(3,1)) plot(post1[1:bugs1$n.sims,1], xlab="iterations",type="l", col=4) plot(post1[1:bugs1$n.sims,2], xlab="iterations",type="l", col=4) plot(post1[1:bugs1$n.sims,3], xlab="iterations",type="l", col=4) ``` 事後分布をヒストグラムで示す。 ```{r} par(mfrow=c(1,3)) hist(post1[,1],freq=FALSE,xlab="beta[1]",main="Posterior distribution of beta1") hist(post1[,2],freq=FALSE,xlab="beta2",main="Posterior distribution of beta2") hist(post1[,3],freq=FALSE,xlab="S",main="Posterior distribution of S") par(mfrow=c(1,1)) ``` # 例で慣れるR+openBUGS 例をなぞりながら、bugs()関数の実効オプション、モデルファイルの意味合い・書き方を確認して行くことにする。 ## 0か1かの確率の推定 今、ある商品Aの後継商品Bを作成したとして、AとBとのどちらが好まれるかを知りたいとする。Bの方がより好まれる確率(pb)は、非常に高くて1かもしれないけれど、逆に全く評価されず、Aの方が好まれる確率が1(Bが好まれる確率が0)かもしれない。 まったく予想がつかないとする。 モニターを募って、何人(n人)かの人にA/Bどちらを好むかを答えてもらった上で、Bをより好む人(nb人)の割合を推定したいとする。 ここでは、問題を単純にするために、必ずどちらか片方を好むものとする。 まず、モニター開始前のpbは0-1区間で一様分布であると想定する。 n人中nb人がBを好むと答える確率は、pbを用いて $$ \frac{n!}{nb!(n-nb)}pb^{nb}(1-pb)^{n-nb} $$ と表せるだろう。 二項分布である。 この式のように表されると考えるのは、「各モニターが前後のモニターに影響されていない」などの条件をつけたときに成り立つ式であることなどを考えれば、「モデルとしてこのような式を採用する」と仰々しく述べてもよい。 これがモデルである。 ```{} model { nb ~ dbin(p, n) p ~ dbeta(1, 1) } ``` この内容を"model1.txt"という名前でRのワーキングディレクトリに保存しておけばよい。 同様のファイルをRの中から作成するには次のようにする。 ```{r} model1 <- function(){ # Model nb ~ dbin(p,n) # Prior p ~ dbeta(1,1) } file.name <- "model1.txt" write.model(model1,file.name) ``` ```{r,warning=FALSE,message=FALSE} data1 <- list(n=10,nb=4) in1 <- list(p=0.5) inits <- list(in1) param <- c("p") file.name <- "model1.txt" model1 <- file.name n.iter <- 300 bugs1 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=n.iter, n.burnin=0, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs1) plot(bugs1) ``` ```{r} post1 <- bugs1$sims.matrix apply(post1,2,mean) apply(post1,2,sd) ``` ```{r} hist(post1[,1],freq=FALSE,xlab="p",main="Posterior distribution of p") ``` これはベータ分布$$ \beta(nb+1,n-nb+1)$$になるはずである。 ベータ分布乱数と比較してみる。 ```{r} r.beta <- rbeta(n.iter,data1$nb+1,data1$n-data1$nb+1) plot(sort(post1[,1]),sort(r.beta)) abline(0,1,col=2) ``` ではこの単純な例でやっている内容を確認してみる。 ### モデルファイル まずはモデルファイルについて確認する。 モデルファイルでは、分布関数を用いて表現する。openBUGSの分布関数は(基本的には)winBUGSのそれと同じである。 winBUGSの分布関数については、http://d.hatena.ne.jp/ryamada22/20140329 を参照。 さて、以下のモデルファイルでは、dbin(),dbeta()という2つの分布関数が用いられている。二項分布関数とベータ関数である。 ```{} model { # Model nb ~ dbin(p,n) # Prior p ~ dbeta(1,1) } ``` 1行目は、Bを好む確率がpのときに、n人に訊いたら、nb人が「Bを好む」ことが二項分布に従って定まることを示している。 今、BUGSを回すときにはnとnbとを与えて、適切なpの分布をしミューレーションで示そうとしていることを示している。 他方、2行目はpとしてどんな分布を事前分布を想定しているかを表している。 2つのパラメタが1,1であるようなベータ分布であることを示している。 実行に際しては、このベータ分布からpをランダムに発生し、それを二項分布に与え、nのもとでnbになるかどうかでそのpの乱数を採択するかどうかを決める。 dbeta(1,1)とは ```{r} p <- seq(from=0,to=1,length=1000) db <- dbeta(p,1,1) plot(p,db) ``` でわかるように、0から1までの一様分布であるから、dunif(0,1)という分布を指定しても同じである。 実際にやってみる。 ```{} model { # Model nb ~ dbin(p,n) # Prior p ~ dunif(0,1) } ``` ```{r} model1.1 <- function(){ # Model nb ~ dbin(p,n) # Prior p ~ dunif(0,1) } file.name <- "model1.1.txt" write.model(model1.1,file.name) ``` ```{r,warning=FALSE,message=FALSE} data1 <- list(n=10,nb=4) in1 <- list(p=0.5) inits <- list(in1) param <- c("p") file.name <- "model1.1.txt" model1 <- file.name # 実行 n.iter <- 300 bugs1.1 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=n.iter, n.burnin=0, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") ``` 一様分布を事前分布に指定しても得られる値の出現順は異なるが、分布としては同じ結果が得られている。 ```{r} post1.1 <- bugs1.1$sims.matrix (head(post1[,1])) (head(post1.1[,1])) plot(sort(post1[,1]),sort(post1.1[,1])) abline(0,1,col=2) ``` このように同じ事前分布なのに、あえてベータ分布を用いたのは、dbeta(1,1)という一様分布でないような分布を使う場合を考えると、二項分布の共役事前分布として、異なる形の事前分布に変えやすいからである。 ### 実行条件 bugs()関数にはデータ、初期値、パラメタ名、モデルファイル、debug、program、bugs.directoryのほかにいくつかの情報を与える。 それぞれを説明する * n.chains * MCMCでは初期値と乱数列を使って処理をするが、初期値を変えて何度か実行する方がよいこともあり、その回数を指定する * n.iter * 推定対象は多数の値が作る分布として判断するわけだが、その作るべき値の数を示す。ただし、そのうち、初めの方のn.burnin個は捨てるので、実際に推定される分布として使用可能なのはn.iter-n.burnin個になる * n.burnin * 上述したように、初めのn.burnin個は捨てる * 今回のように一番初め値から、推定に用いることが適切な場合にはn.burnin=0でも構わない * n.thin * 非常に多くの値を発生させるのは、その方が、初期値の影響が混入することを避けることができるからであるが、あまりにたくさんだと大変なので、n.iterが大きいときには、何個かおきに記録してそれ以外を捨てることも有効である。n.iter=1ならば全部を記録し、n.iter=2ならば一つおきに捨てる、とそういう具合である。 n.chains,n.iter,n.burnin,n.thinの値を変えながら実行して、出力がどのように変わるかを確認してみる。 n.chains=1でn.iter=100,n.burnin=10,n.thin=3としてみる。 ```{r,warning=FALSE,message=FALSE} bugs1.2 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=100, n.burnin=10, n.thin=3, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs1.2) ``` n.iter-n.burnin = n.thin*bugs1$n.simsとなっていることがわかる。 次にn.chains=3、n.thin=2でやってみる。初期値をn.chains通り、指定する必要がある。 ```{r} in1 <- list(p=0.5) in2 <- list(p=0.3) in3 <- list(p=0.7) inits <- list(in1,in2,in3) inits ``` このように初期値を3通りリストとして準備している。 さて、実行してみる。 ```{r,warning=FALSE,message=FALSE} bugs1.3 <- bugs(data1, inits, param, model.file=model1, n.chains=3, n.iter=100, n.burnin=10, n.thin=2, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") ``` ```{r} print(bugs1.3) ``` 各chainについてn.iter回をn.burnin込みで実施していることが記載されている。 ## 正規分布の平均と分散とを推定する 比較的ふんだんに発現していると思われる遺伝子mRNAをある検出手法で測定したときの値の分布について推定することを考える。 検出手法についてもあまりよくわかっていないので、平均がいくつで分散がいくつになるか、さっぱり予想がつかないが、正規分布に従うだろうことは予想してもよいとする。 このような場合のモデルは以下のようになる。 "model2.txt"というファイルで保存しておくこととする。 ```{} model { for (i in 1:N) { y[i] ~ dnorm(mu, S) } mu ~ dnorm(0, 0.0001) S ~ dgamma(0.0001,0.0001) } ``` ```{r} model2 <- function(){ # Model for (i in 1:N) { y[i] ~ dnorm(mu, tau) } # Prior mu ~ dnorm(0, 0.0001) tau ~ dgamma(0.0001,0.0001) } file.name <- "model2.txt" write.model(model2,file.name) ``` このモデル設定では、N個の観察値を一つのmu,tauのセットに基づいて正規分布に従うことを示している。 muには、第1引数(v1 平均)0、第2引数(v2 tau) 0.0001の正規分布を事前分布として想定している。 このv2が小さいということは、分散が大きいということであるので、この事前分布は、0を中心として、非常に裾が長い分布である。 要するに、いろいろな値をほぼ同確率で想定していることになる。 v2の値を変化させて、どのような事前分布になるのかを表示してみる。 v2の値が小さくなるほど平坦な分布となることを、実数と対数とで示す。 横軸の中央付近にピークがあることに着目するのではなく、そこにピークはあるものの、それはごく限られた幅に納まり、それ以外の広い範囲で平坦になっていることが、この分布を採用した理由である。 ```{r,warning=FALSE} x <- seq(from=-100,to=100,length=1000) v2s <- 10^(0:(-5)) d <- matrix(0,length(x),length(v2s)) for(i in 1:length(v2s)){ v2 <- v2s[i] d[,i] <- dnorm(x,0,1/sqrt(v2)) } par(mfcol=c(1,2)) matplot(x,d,type="l") matplot(x,log(d),type="l") par(mfcol=c(1,1)) ``` また、標準偏差の逆数としのtauの事前分布はガンマ分布を用いている。 ガンマ分布が選ばれているのは、tauには正の値をとりたいからである。 そのような理由でガンマ分布を採用したうえで、次にその形を決めたい。 dgamma(a,b)で指定されるガンマ分布は、平均が$$\frac{a}{b}$$分散が$$\frac{a}{b^2}$$であるが、事前分布としてはさまざまな値をとりたい、言い換えると分散を大きくしたい。 ガンマ分布の分散は$$\frac{a}{b^2}$$であるので、a=bとして小さい値を与えることで、平均は1で分散の大きい分布が得られる。 これが、tauの事前分布の選び方である。 事前分布としての指定に際してはa,bに等しく、小さい値を与えているが、これは、平均$\frac{a}{b}=\frac{a}{a}=1$が1で分散が大きい分布である。 a,b=aの値を色々に変えてガンマ分布の様子をプロットしてみる。 ```{r} x <- seq(from=0,to=20,length=1000) as <- 10^(0:(-7)) d <- matrix(0,length(x),length(as)) for(i in 1:length(as)){ d[,i] <- dgamma(x,as[i],as[i]) } par(mfcol=c(1,2)) matplot(x,d,type="l") matplot(x,log(d),type="l") par(mfcol=c(1,1)) ``` 0付近にピークが残るも、aが小さくなるにつれ、平坦な分布となることがわかる。 ではデータを作成して推定してみる。 ```{r,warning=FALSE,message=FALSE} N <- 100 mu <- 5 sd <- 2 y <- rnorm(N,mu,sd) data1 <- list(y=y,N=N) in1 <- list(mu=0,tau=1) inits <- list(in1) param <- c("mu","tau") file.name <- "model2.txt" model2 <- file.name n.iter <- 1000 bugs2 <- bugs(data1, inits, param, model.file=model2, n.chains=1, n.iter=n.iter, n.burnin=100, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs2) ``` ここで推定されたのは$$\tau=\frac{1}{sd^2}$$であるので、データ生成時に与えたsd=2に近い値が推定されたかを確認するために計算しておく。 また、サンプル平均、サンプルに基づくsdも計算しておく。 ```{r} post2 <- bugs2$sims.matrix mean(post2[,1]) mean(1/sqrt(post2[,2])) # サンプル平均とサンプルからの標準偏差 mean(y) sd(y) ``` その上で分布を示す。 赤は真値、緑はサンプルから算出した平均とsdである。 ```{r} par(mfcol=c(1,2)) hist(post2[,1],freq=FALSE,xlab="mu",main="Posterior distribution of mu") abline(v=mu,col=2) abline(v=mean(y),col=3) hist(1/sqrt(post2[,2]),freq=FALSE,xlab="sd",main="Posterior distribution of sd") abline(v=sd,col=2) abline(v=sd(y),col=3) par(mfcol=c(1,1)) ``` ## 線形回帰をやってみる $$ \begin{equation} y = beta0 + beta1 \times x1 + beta2 \times x2 + \epsilon\times z\\ z ~ N(0,1) \end{equation} $$ という線形回帰をしてみよう。冒頭の「ひとまず回す」の例では、説明変数が1つの線形回帰だったが、今回は2つにしてみる。 具体性を持たせるためにx1を年齢、x2を体重、yを最高血圧として考えよう。 値とその分布の妥当性はここでは問わ無いことにする。 まずはデータを作る。 ```{r} N <- 500 # 年齢 x1 <- sample(20:100,N,replace=TRUE) # 体重 x2 <- rnorm(N,65,10) beta0 <- 30 beta1 <- 0.5 beta2 <- 1 epsilon <- 10 y <- beta0 + beta1*x1+beta2*x2+epsilon * rnorm(N) hist(y) # yの値で色を付けて、散布図にする st.y <- (y-min(y))/(max(y)-min(y)) col <- rgb(st.y,1-st.y,1) plot(x1,x2,pch=20,col=col,xlab="age",ylab="weight",main="systolic pressure") ``` モデルファイルを作り、"model3.txt"として保存する。 項の数が増えたが、N人それぞれについて、個人の年齢x1[i]と体重x2[i]に応じて、最高血圧の予想値mu[i]を求めその値を平均とした正規分布に従うことを示してる。 パラメタbeta0,beta1,beta2,epsilonに事前予想が立たないと仮定すれば、 beta0,beta1,beta2は0を中心とした分散の大きな正規分布を事前分布とし、 乱雑項も分散が不明な正規分布とするのがよいので、そのような分布が指定してある。 ```{} model { for (i in 1:N) { y[i] ~ dnorm(mu[i], tau) mu[i] <- beta0 + beta1 * x1[i] + beta2 * x2[i] } beta0 ~ dnorm(0,0.0001) beta1 ~ dnorm(0,0.0001) beta2 ~ dnorm(0,0.0001) tau ~ dgamma(0.0001,0.0001) } ``` ```{r} model3 <- function() { for (i in 1:N) { y[i] ~ dnorm(mu[i], tau) mu[i] <- beta0 + beta1 * x1[i] + beta2 * x2[i] } beta0 ~ dnorm(0,0.0001) beta1 ~ dnorm(0,0.0001) beta2 ~ dnorm(0,0.0001) tau ~ dgamma(0.0001,0.0001) } file.name <- "model3.txt" write.model(model3,file.name) ``` さて、実行する。 ```{r,warning=FALSE,message=FALSE} data1 <- list(y=y,x1=x1,x2=x2,N=N) in1 <- list(beta0=0,beta1=0,beta2=0,tau=1) inits <- list(in1) param <- c("beta0","beta1","beta2","tau") file.name <- "model3.txt" model1 <- file.name # 実行 bugs3 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=1100, n.burnin=100, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs3) ``` ```{r} post3 <- bugs3$sims.matrix apply(post3,2,quantile,c(0.1,0.5,0.9)) ``` beta0,beta1,beta2が良い推定値になっていることがわかる。 ## 招待選手と一般参加選手の2群〜混合分布〜 今、全部でN人がエントリーしている100m走大会があるとする。 このうち、pi[1]の割合で招待選手(群 g=1)、pi[2]の割合で一般参加選手(群 g=2)であるとする。 招待選手のタイムは平均mm[1]標準偏差ss[1]、一般参加選手はmm[2],ss[2]の正規分布に従うとする。 ただし、この招待選手というのは、100m走の速さを基準に招待されたわけではなく、マラソンが得意であることで招待されたという。 招待選手はアスリートなので、一般参加選手よりも100m走のパフォーマンスがよいようにも思えるし、大差ないかもしれないし、かえって遅いかもしれない。 pi[1],pi[2]の事前確率は0-1の範囲で全く不明だという。 データを作成してみる。 ```{r} N <- 1000 pi <- c(0.2,0.8) n1 <- N*pi[1] n2 <- N-n1 mm <- c(12,16) ss <- c(1,2) # 100m走のタイム y1 <- rnorm(n1,mm[1],ss[1]) y2 <- rnorm(n2,mm[2],ss[2]) y12 <- c(y1,y2) # グループ g12 <- c(rep(1,n1),rep(2,n2)) # 選手番号をランダムにつける ord <- sample(1:N) # 選手番号順に並べ替える。これが観察データ y <- y12[ord] g <- g12[ord] h <- hist(y,plot=FALSE) hist(y1,breaks=h$breaks,density=20,col=2,ylim=c(0,max(h$counts))) hist(y2,breaks=h$breaks,density=17,col=3,add=TRUE) ``` ではモデルを立ててみる。 各選手のグループは確率pにより1か2に決まる。 そのpは一様分布を事前確率とする。 各選手のタイムはグループ1か2かによって平均、標準偏差を変える必要があるが、それらに基づく正規分布に従う。 2つのグループのタイムを決める平均と標準偏差はm1,m2,s1,s2とするが、m1,m2は9秒から30秒の範囲で一様分布を想定しよう。s1,s2は全く不明として、正の値を分散の大きいガンマ分布で与えることとする。 ```{} model { for (i in 1:N) { y[i] ~ dnorm(m[i], tau[i]) m[i] <- mm[g[i]] tau[i] <- tt[g[i]] g[i] ~ dcat(pi[]) } pi[1:2] ~ ddirch(alpha[]) mm[1] ~ dunif(9, 30) mm[2] ~ dunif(9, 30) tt[1] ~ dgamma(1.00000E-04, 1.00000E-04) tt[2] ~ dgamma(1.00000E-04, 1.00000E-04) } ``` ```{r} model4 <- function() { for (i in 1:N) { y[i] ~ dnorm(m[i], tau[i]) m[i] <- mm[g[i]] tau[i] <- tt[g[i]] g[i] ~ dcat(pi[]) } pi[1:2] ~ ddirch(alpha[]) mm[1] ~ dunif(9,30) mm[2] ~ dunif(9,30) tt[1] ~ dgamma(0.0001,0.0001) tt[2] ~ dgamma(0.0001,0.0001) } file.name <- "model4.txt" write.model(model4,file.name) ``` さて実行しよう。 ```{r,warning=FALSE,message=FALSE} alpha <- c(1,1) data1 <- list(y=sort(y),g=c(1,rep(NA,N-2),2),alpha=alpha,N=N) in1 <- list(pi=c(0.5,0.5),mm=c(15,15),tt=c(1,1)) inits <- list(in1) param <- c("pi","mm","tt") file.name <- "model4.txt" model1 <- file.name # 実行 bugs4 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=1100, n.burnin=100, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs4) ``` 2群の割合と2群の平均がよい感じに推定されていることがわかる。 推定されたtauから標準偏差を計算し、データ生成に用いたそれがよく推定されていることも確認できる。 ```{r} post4 <- bugs4$sims.matrix apply(post4,2,quantile,c(0.1,0.5,0.9)) mean(1/sqrt(post4[,5])) mean(1/sqrt(post4[,6])) ``` ## n次線形回帰をしてみる $$ y = \sum_{i=0}^n b_i x^i + \epsilon z $$ (ただしzは標準正規分布に従う乱雑項) のようなデータから、n+1個のbの値を推定してみる。 まずはデータ作成。ただし、三角関数を使って作成する。 ```{r} N <- 100 x <- sort(rnorm(N)) y <- 3*sin(x) epsilon <- 0.5 z <- rnorm(N) y <- y + epsilon * z plot(x,y,pch=20) ``` モデルファイルを作る。 ```{r} model5 <- function() { for (i in 1:N) { y[i] ~ dnorm(m[i], tau) m[i] <- b[1]+b[2]*x[i] + b[3]*x[i]*x[i] + b[4] * pow(x[i],3) } for(i in 1:(n+1)){ b[i] ~ dnorm(0,0.0001) } tau ~ dgamma(0.0001,0.0001) } file.name <- "model5.txt" write.model(model5,file.name) ``` 実行する。 ```{r} n <- 3 data1 <- list(y=y,x=x,N=N,n=n) in1 <- list(b=rep(0,n+1),tau=1) inits <- list(in1) param <- c("b","tau") file.name <- "model5.txt" model1 <- file.name # 実行 bugs5 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=1100, n.burnin=100, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs5) ``` 推定された係数を用いて、推定線を描いてみる。 ```{r} post5 <- bugs5$sims.matrix out5.coef <- apply(post5,2,mean) plot(x,y,pch=20) x. <- seq(from=min(x)-0.1*(max(x)-min(x)),to=max(x)+0.1*(max(x)-min(x)),length=100) pred.y <- rep(out5.coef[1],length(x.)) for(i in 2:(n+1)){ pred.y <- pred.y + out5.coef[i] * x.^(i-1) } points(x.,pred.y,col=2,type="l") ``` ## カーネル分布推定 N個の値を観測してそこに密度分布を推定するとする。 正規分布をカーネル関数としてカーネル法でやるなら、個々の観測に、ある分散の正規分布を与え、その混合分布として求めることとなる。 混合分布なら、すでに、「100m走大会〜招待選手と一般参加選手」の例でやったので、それを少し改変すればよい。 100m走大会では2群だったが、今度は、データ数Nのすべてを個別の群として扱うので群数はNである。 それぞれの群の寄与度は1/Nで固定である。 推定したいのは、個々の値を中心とした正規分布のその分散をいくつにするかである。 すべての値について分散の値を共通にするのであれば、推定パラメタは一つだけである。 それを書けば以下の通り。 yは観測値のベクトル。 mmもyと同じベクトルであるが、これはBUGS中に採取されるのではなくて、決まった値。 tauは推定パラメタである。 gはN個の群のラベルである。 モデルファイルの中では、個々の値が、1,...,Nのいずれかの群に属するかを等確率で採取し、取られた群g[i]に応じて、正規分布の平均値m[i]が決まり、tauに応じて値が採取している。 piは1,...,Nを等確率で選ぶために与えるベクトルである。 ```{r} model6 <- function() { for (i in 1:N) { y[i] ~ dnorm(m[i], tau) m[i] <- mm[g[i]] g[i] ~ dcat(pi[]) } tau ~ dgamma(0.0001,0.0001) } file.name <- "model6.txt" write.model(model6,file.name) ``` データを作る。 ```{r} y <- c(rnorm(100),runif(100,3,8),rexp(200,4)+10) y <- sort(y) plot(density(y)) ``` ```{r} N <- length(y) alpha <- rep(100,N) data1 <- list(y=y,mm=y,N=N,g=1:N,pi=rep(1/N,N)) in1 <- list(tau=1) inits <- list(in1) param <- c("tau") file.name <- "model6.txt" model1 <- file.name # 実行 bugs6 <- bugs(data1, inits, param, model.file=model1, n.chains=1, n.iter=1100, n.burnin=100, n.thin=1, debug=TRUE, program="OpenBUGS", bugs.directory="C:/Program Files(x86)/OpenBUGS/OpenBUGS323") print(bugs6) ``` 推定された係数を用いて、推定線を描いてみる。density()の結果と似ている。 ```{r} post6 <- bugs6$sims.matrix out6.coef <- apply(post6,2,mean) x <- seq(from=min(y)-(max(y)-min(y))*0.3,to=max(y)+(max(y)-min(y))*0.3,length=100) pred.d <- rep(0,length(x)) for(i in 1:length(y)){ pred.d <- pred.d + dnorm(x-y[i],1/sqrt(out6.coef[1]))/length(y) } par(mfcol=c(1,2)) plot(x,pred.d,type="l") plot(density(y)) par(mfcol=c(1,1)) ```