準備
多項ロジスティック回帰について
ポリア・ガンマ分布を用いた多項ロジスティック回帰のギブスサンプラー - ジョンとヨーコのイマジン日記
に書いた. たぶんこちらを先に読んだほうがいい.
ここではポアソン回帰, つまり次のモデルを考える.
ところで, ポアソン分布は平均と分散が同じなので, ポアソン分布より分散の大きいカウントデータのモデリングには負の二項分布が使われることがある.
負の二項分布は次の確率関数を持つ.
(パラメータの置き方は統計ソフトによって微妙に違うことがある.)
負の二項分布は の極限でポアソン分布になる. たとえば,
mathematical statistics - Poisson as a limiting case of negative binomial - Cross Validated
を参照してほしい.
ここから, に適当に大きい数字を入れて負の二項分布の尤度を計算すれば, ポアソン分布と大体一致するのではないかと思いつく.
この方針で少し負の二項分布の式を変形してみる.
となるように を置くと,
さらに と改めて置くと, 負の二項分布のサンプル1つあたりの尤度 は,
と表せ, 結果, ポリア・ガンマ分布の性質がそのまま使える.
の形で回帰構造を入れ, の事前分布を正規分布
とすると, このとき full conditional はポリア・ガンマ分布と多変量正規分布を用いて、
となる. ここで,
と置いた.
また, , は を対角成分とする対角行列とした.
R による実装例
library(BayesLogit) library(ggplot2) gibbs_nbinom <- function(y,n,X,tau,iter){ N <- length(y) d <- ncol(X) B <- diag(tau, d) beta_tilde <- matrix(0, iter, d) beta_tilde[1,] <- rnorm(d) logn <- log(n) m <- y + n for(i in 2:iter){ kappa <- 0.5*y-0.5*exp(logn) eta <- X%*%beta_tilde[i-1,]-logn omega <- rpg(N, m, eta) Omega <- diag(omega) Vinv <- t(X)%*%Omega%*%X + B U <- chol(Vinv) A <- forwardsolve(t(U), t(X)%*%(kappa+logn*omega)) mu <- backsolve(U, A) #equivalent to #mu <- solve(Vinv%*%(t(X)%*%(y-0.5*n))) beta_tilde[i,] = mu + backsolve(U, rnorm(d)) #multiply to inverse of U } return(list(beta=beta_tilde)) } set.seed(1234) beta <- c(2,0.5) X <- matrix(runif(2*100),100,2) y <- rpois(100,exp(X%*%beta)) print(max(y)) out_sample <- gibbs_nbinom(y=y,n=100,X=X,tau=1,iter=4000) dfs <- expand.grid(iter=1:4000, index=1:2) dfs$value <- as.vector(out_sample$beta) dft <- data.frame(beta=beta, index=1:2) ggplot(dfs, aes(x=iter, y=value))+ geom_line(colour="darkgrey")+ geom_hline(data=dft, aes(yintercept=beta), colour="royalblue")+ facet_grid(index~., scales = "free", labeller = label_both)+ theme_classic(14)+ theme(strip.text.y = element_text(angle = 0), axis.text = element_text(colour = "black")) #ggsave("tracep.png") lp_pois <- function(beta){ sum(dpois(y,exp(X%*%beta), log = TRUE))+sum(dnorm(beta,log=TRUE)) } lp_negbin <- function(beta,n){ sum(dnbinom(y,size=n,mu=exp(X%*%beta), log = TRUE))+sum(dnorm(beta,log=TRUE)) } burnin <- 1:500 dfp <- data.frame(out_sample$beta[-burnin,]) colnames(dfp) <- c("b1","b2") df <- expand.grid(b1=seq(1.5,2.5,by=0.005),b2=seq(0,1,by=0.005)) lp_v_p <- apply(df, 1, function(b){lp_pois(c(b[1],b[2]))}) lp_v_nb <- apply(df, 1, function(b){lp_negbin(c(b[1],b[2]), 100)}) ggplot(df, aes(x=b1, y=b2))+ geom_contour(aes(z=exp(lp_v_p), colour="poisson"))+ geom_contour(aes(z=exp(lp_v_nb), colour="negbin"))+ geom_point(data=dfp, alpha=0.1)+ scale_colour_manual(values = c("royalblue","orange2"))+ labs(colour="likelihood")+ theme_classic(16) #ggsave("post.png")
としてポアソン分布でデータを生成し, の負の二項分布で推定しました.
折れ線グラフで見ると の事後分布はシミュレーションで設定した正解の近くにばらついているようです.
尤度をポアソン分布にした場合と負の二項分布にした場合で事後分布を比較します.
等高線は尤度と事前分布の積をパラメータの関数と見たものです. 定数倍の違いを無視したらこれは正確な事後分布と一致します. この場合は負の二項分布でやっても二項分布でやっても大差ないことがわかります.
点はギブスサンプリングで得られた乱数です. 事後分布に近いものが得られています.
どの程度の なら十分大きいと言えるかはデータのスケールによるでしょう.
をさらに大きくしてやると, ギブスサンプラーは自己相関が大きくなる印象です.
メトロポリス・ヘイスティングス法などで についてもデータから決めることもできるでしょう.
というか現実的には, 単純なポアソン回帰なら最尤法かMAP法でいいような気がしますが, ポアソン分布を使ったモデルを魔改造したい場合には, こういうテクニックが使える場合もあるかもしれません.