rstanで簡単にglmmができるglmmstan()を作ってみた

66
rstan でででで GLMM でででで glmmstan() でででででで 2015 で 6 で 13 で SapporoR #4 @simizu706

Upload: hiroshi-shimizu

Post on 28-Jul-2015

1.228 views

Category:

Software


3 download

TRANSCRIPT

Page 1: rstanで簡単にGLMMができるglmmstan()を作ってみた

rstanで簡単に GLMMができるglmmstan()を作ってみた

2015年 6月 13日SapporoR #4

@simizu706

Page 2: rstanで簡単にGLMMができるglmmstan()を作ってみた

自己紹介• 清水裕士(@simizu706)

– 関西学院大学社会学部– 兵庫県西宮市にあります

• 専門– 社会心理学っぽいこと

• 趣味– 心理統計,統計ソフト開発– 最近は Stanとか

• Web:– http://norimune.net

Page 3: rstanで簡単にGLMMができるglmmstan()を作ってみた

Excelで動くフリーの統計ソフト HAD

Page 4: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日は Rの勉強会

Page 5: rstanで簡単にGLMMができるglmmstan()を作ってみた

【※注意※】• この発表は(かなり)マニアックです– GLMM,ベイズ統計,MCMC, rstan ・・・–必要な事前知識が多いですが,ぼーっと聞いておいてください

• 発表者は早口です– 30分でスライド 64枚を疾走します

Page 6: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日のお話• GLMMってやっぱほら,MCMCじゃない?

• glmmstan()という代筆関数を作った

• glmmstan()を使ってみた

• まとめ

Page 7: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日のお話• GLMMってやっぱほら,MCMCじゃない?

• glmmstan()という代筆関数を作った

• glmmstan()を使ってみた

• まとめ

Page 8: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日使うデータ• 野球のデータ– 2014年のプロ野球野手 140名の打撃成績と翌年の年俸

– プロ野球 Freakからダウンロードできる• http://baseball-freak.com/• (ただし,年俸のデータはWikipediaから集めた)

• 知りたいこと– ホームラン数はどういう分布でモデリングできる?– ホームラン一本打ったら,年俸はいくら増えるの?

Page 9: rstanで簡単にGLMMができるglmmstan()を作ってみた

ホームランの本数をモデリング• まずは度数分布を確認

・・・ポアソン分布?でもどう考えても個人差が・・・

GLMMだ!

Page 10: rstanで簡単にGLMMができるglmmstan()を作ってみた

年俸をホームラン数で予測したい

Page 11: rstanで簡単にGLMMができるglmmstan()を作ってみた

年俸をホームランで予測したい

( G) LMMだ!

球団ごとに回帰直線が違う・・・

Page 12: rstanで簡単にGLMMができるglmmstan()を作ってみた

GLMMってなんだっけ• Generalized Linear Mixed Modeling–一般化線形混合モデル–線形モデル+指数分布族+変量効果

• どういうときに GLMMを使うのか?–データが離散分布に従うが,過分散が生じるとき• 個体差が大きい場合

–データがネストされた構造になっていて,グループごとに効果が異なるとき

Page 13: rstanで簡単にGLMMができるglmmstan()を作ってみた

いつもの

by 久保先生のWebから

Page 14: rstanで簡単にGLMMができるglmmstan()を作ってみた

みどり本

Page 15: rstanで簡単にGLMMができるglmmstan()を作ってみた

GLMMがMCMCな理由• 推定上の問題

• モデル比較の問題

Page 16: rstanで簡単にGLMMができるglmmstan()を作ってみた

GLMMにおける最尤法の困難• 尤度関数が異なる分布の積の形になる

• これを解くには積分計算が必要–変量効果のグループが 1つなら,頑張って数値積分することができる

–でも 2つ以上になると,近似計算が必要• 場合によっては,バイアスが生じる

Page 17: rstanで簡単にGLMMができるglmmstan()を作ってみた

そこでMCMCを使ったベイズ推定

• 積分計算を避けられる–事後分布を積分計算をせずにシミュレーションで推定する

• その他,最尤法に対するアドバンテージ–事後分布が正規分布でなくてもよい–分散成分の推定にバイアスが生じない• 最尤法は分散成分が不偏推定量ではない• 特に小サンプルでバイアスが大きい

Page 18: rstanで簡単にGLMMができるglmmstan()を作ってみた

最尤法におけるモデル選択• モデル比較といえば AIC– でも AICはモデルが真の分布を含んでいる必要がある

• つまり,データがどの分布に従うかを決めるのには使えない

– AICは事後分布が正規分布に従う必要がある• しかし,多くの GLMMの変量効果の分散成分の事後分布は正規分布にならない

• もっと柔軟につかえる情報量規準はないの?– それがWAIC!– MCMCを使うと簡単に計算ができる

Page 19: rstanで簡単にGLMMができるglmmstan()を作ってみた

WAICかわいいよWAIC

• 広く使える情報量規準– Widely Applicable information Criterion– Watanabe Akaike Information Criterionとも

• WAICの利点(渡辺先生のWebサイトから)– 真の分布・事前分布がどのような場合でも使える– 事後分布が正規分布でなくても使える

• 仮に正規分布で近似できても従来法より正確– 正則モデルでなくても使える– 簡単に計算できる

Page 20: rstanで簡単にGLMMができるglmmstan()を作ってみた

WAICを使うと・・・• 残差の分布族をこえてモデル選択できる?

– たぶん

• どの事前分布が適切かが選択できる– らしい

• AICで比較できることはWAICで全て可能– AICは統計的に正則で真の分布を含む場合,WAICに一致

• WAIC使うっきゃない!– 「 WAICは現状もっとも有力かつ汎用的な、 MCMCから算出できる予測のよさの指標である」 by 岡田先生

Page 21: rstanで簡単にGLMMができるglmmstan()を作ってみた

MCMCソフトウェア事情• MCMCglmm パッケージ

– 比較的簡単にGLMMをMCMCできる– 変量効果が複数あるとほぼ推定できない

• BUGS– コードを書けば,いろんなモデルを推定できる– 相関が高い変量効果の推定では,いつまでたっても収束しないという事態がある(らしい)

• Stan– 複雑な階層ベイズのモデルでも早く収束する– NUTSという最新のMCMCアルゴリズムを使っている

Page 22: rstanで簡単にGLMMができるglmmstan()を作ってみた

stanかわいいよ stan

• フリーのベイズ推定(MCMC)用のソフト– R上からでも rstan パッケージをいれると動かせる

• rstan パッケージのインストール– C++ コンパイル用のツールをインストール– Githubからダウンロード+インストール– 山口大学の小杉先生の資料がわかりやすい

• http://www.slideshare.net/KojiKosugi/r-stan

Page 23: rstanで簡単にGLMMができるglmmstan()を作ってみた

今月中に発売予定• 基礎からのベイズ統計学– ハミルトニアンモンテカルロ法による実践的

入門– 豊田秀樹著

– Stanについての初めての日本語の本

Page 24: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日のお話• GLMMってやっぱほら,MCMCじゃない?

• glmmstan()という代筆関数を作った

• glmmstan()を使ってみた

• まとめ

Page 25: rstanで簡単にGLMMができるglmmstan()を作ってみた

GLMMを Stanでやりたい• でも Stanは初心者には敷居が高い–データの読み込みとそれに対応した変数の宣

言など,慣れないとぱっとさっとはできない

• Rのコードだけ書いて,ぱぱっと GLMMしたい–たとえば・・・ glmer()と同じ書き方をしたらできる,みたいな。

Page 26: rstanで簡単にGLMMができるglmmstan()を作ってみた

なんかそんなの聞いたことが・・・?

Page 27: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmer2stan パッケージ• lme4 文法で簡単にMCMCができる– WAICも計算してくれる– すてきやん?それでええやん?

• しかし,いろいろ不満がある– 推定が妙に遅い– 変数名に依存するので毎回コンパイルが必要– 謎のエラーが頻発する– 使える分布が限られる– コードがいじりにくい

Page 28: rstanで簡単にGLMMができるglmmstan()を作ってみた

で,新しい関数を作った• glmmstan()– lme4タイプの式を入力すると,内部で stan コードを自動生成し, stanでMCMCを走らせる

– 基本は glmer2stanと同じ– source(“http://bit.ly/glmmstan”) で読み込める

• 必要パッケージ– rstan パッケージ

• stanがないと始まらない– doParallel パッケージ

• 並列化処理に必要• なくても並列化しなければ一応走る

Page 29: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmer2stanとの違い• glmmstanのほうが推定が速い–ベクトル化して書いてるので,その分計算が

速い• glmer2stanはあえてベクトル化せず書いてるらしい

–後述する,並列化を使うことでさらに速い

glmer2stan

Page 30: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmer2stanとの違い• コンパイルを避けられる–変数名に依存しないので,固定効果を変えるだけなら,コンパイルしなくてもいい

– コンパイル済みの stanモデルの出力も可能

• stan コードをいじりやすい– stan コードだけを出力して,それを編集し,そのコードで分析ができる

–事前分布を変えたり,微調整がしやすい

Page 31: rstanで簡単にGLMMができるglmmstan()を作ってみた

使える分布• 正規分布(” gaussian” or “normal”)• ベルヌーイ分布(” bernoulli”) ロジットリンク• 二項分布(” binomial”) ロジットリンク• ポアソン分布(” poisson”) 対数リンク• 負の二項分布(” nbinomial”) 対数リンク• ガンマ分布(” gamma”) 対数リンク• 対数正規分布(” lognormal”) 対数リンク• ベータ分布(” beta”) ロジットリンク• 順序カテゴリカル(” ordered”) ロジットリンク

Page 32: rstanで簡単にGLMMができるglmmstan()を作ってみた

WAICを計算できます• 全てのモデルでWAICを出力– 一応, glmer2stanと一致することは確認

• しかし,本当にあっているのか・・・– 岡田先生の行動計量学会資料を参考に計算

• http://www3.psy.senshu-u.ac.jp/~ken/BSJ2015spring_okada.pdf

– 他にWAICを出力するソフトがないので,イマイチ自信がありません。

– 詳しい方は stan コードを覗いてみて,間違いがあればご指摘いただけると助かります

– 今回はたぶん大丈夫ということで結果を発表します

Page 33: rstanで簡単にGLMMができるglmmstan()を作ってみた

その他の機能• 交互作用項と単純効果の分析– 交互作用項があるとき,スライス変数を指定することで単純効果の分析が可能

–今のところ ±1SDでスライス

• オフセット項を追加できる–みどり本 6 章,「 offset 項わざ」を参照–今のところポアソンか負の二項分布のみ可

Page 34: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日のお話• GLMMってやっぱほら,MCMCじゃない?

• glmmstan()という代筆関数を作った

• glmmstan()の使い方

• glmmstan()を使ってみた

Page 35: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmmstan()の使いかた• 基本的な使いかたは glmerと同じ

• 必須の引数– formula :式を書く  glmerと同じ文法– data :データフレームを指定– family:使用する分布を入力 デフォルトは正規分布

• 戻り値– stanfitクラスのオブジェクトを返す– なので, rstanの出力関数が使える

fit <- glmmstan(salary ~ HR+(1+HR|team), data=dat, family="gaussian")

Page 36: rstanで簡単にGLMMができるglmmstan()を作ってみた

コンパイルを避けたい• 一度分析した出力を stanfitに入れる–変数名に依存しないので,毎回コンパイルしなくてもいい

– 固定効果を変えるだけなら,次のように書くだけで推定が可能

fit1 <- glmmstan(salary ~ HR+(1+HR|team),data=dat, family=“gaussian")

fit2 <- glmmstan(salary ~ HR+(1+HR|team),data=dat, family=“gaussian",

stanfit = fit1)

Page 37: rstanで簡単にGLMMができるglmmstan()を作ってみた

stan コードを修正して分析したい

• stan コードを指定すると優先的に分析– stan コードだけを出力して,それを編集し,そのコードで分析ができる

code1 <- glmmstan(salary ~ HR+(1+HR|team),data=dat, family="gaussian",

codeonly = TRUE)

fit <- glmmstan(salary ~ HR+(1+HR|team),data=dat, family="gaussian",

stancode = code1)

Page 38: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmmstanの stan コード例data{ int<lower=1> N; int<lower=1> P; row_vector[P] x[N]; int<lower=1> R; int<lower=1> G[R]; int<lower=1> Q[R]; real y[N]; int<lower=1> id1[N]; row_vector[Q[1]] z1[N];} transformed data{ vector[Q[1]] mu1; for(q in 1:Q[1]) mu1[q] <- 0;} parameters{ vector[P] beta; vector[Q[1]] r1[G[1]]; vector<lower=0>[Q[1]] tau_sd1; corr_matrix[Q[1]] tau_corr1; real<lower=0> s;}

transformed parameters{ real<lower=0> sigma; cov_matrix[Q[1]] tau1; sigma <- s^2; tau1 <- quad_form_diag(tau_corr1,tau_sd1);} model{ real predict[N]; beta ~ normal(0,1000); r1 ~ multi_normal(mu1,tau1); tau_sd1 ~ cauchy(0,2.5); tau_corr1 ~ lkj_corr(2); s ~ cauchy(0,2.5); for(n in 1:N){ predict[n] <- x[n]*beta+z1[n]*r1[id1[n]]; } y ~ normal(predict, s);} generated quantities{ real log_lik[N]; real predict[N]; for(n in 1:N){ predict[n] <- x[n]*beta+z1[n]*r1[id1[n]]; log_lik[n] <- normal_log(y[n], predict[n], s); }}

Page 39: rstanで簡単にGLMMができるglmmstan()を作ってみた

その他の機能• 交互作用項と単純効果の分析

• オフセット項を追加できる–今のところポアソンか負の二項分布の場合のみ

fit <- glmmstan(salary ~ HR*AVG+(1+HR|team), data=dat, family="poisson", center = TRUE, slice="AVG")

fit <- glmmstan(salary ~ HR+(1+HR|team),data=dat, family="poisson", offset = "ATbase") ※Log()をつけなくてもい

Page 40: rstanで簡単にGLMMができるglmmstan()を作ってみた

並列化処理• chainごとに並列化したほうが計算が速い– parallel = Tと書けば並列化可能–あるいは, Pglmmstan()関数を使ってもよい

– コア数は cores=で指定• デフォルトは chainsと同じ

fit <- Pglmmstan(salary ~ HR+(1+HR|team),data=dat, family="gaussian", chains = 4, cores = 4)

Page 41: rstanで簡単にGLMMができるglmmstan()を作ってみた

並列化• 4chainでも別に 4 倍速になるわけではないが・・– 基本的には常に並列化するのがオススメ– いらん informational messagesがでなくなるのもいい

• 並列化が「ない」とき

• 並列化が「ある」とき

Page 42: rstanで簡単にGLMMができるglmmstan()を作ってみた

※注意• ものすごい informational Messagesが出る–でも,これはエラーではなく,推定は問題ない

– 赤字で出るので最初はたぶんビビる

Page 43: rstanで簡単にGLMMができるglmmstan()を作ってみた

stanに関する引数• MCMCについての引数– iter:サンプリング回数 デフォルトは 2000– warmup:バーンイン期間 デフォルトは iterの半分– chains:マルコフ連鎖の数 デフォルトは 2– thin: 何回おきに採用するか デフォルトは 1

• stanにいれる便利な引数– stancode:いじった stan コードを入力する– standata:いじった stanにいれる dataを入力する– stanmodel: コンパイル済みのモデルを入力する– stanfit : stanの出力を入力する(コンパイルを避ける)

Page 44: rstanで簡単にGLMMができるglmmstan()を作ってみた

その他の引数• Stanに入れるためのオブジェクトを返す– codeonly: TRUEで stan コードだけを返す– dataonly: TRUEで stan 用のデータだけを返す– modelonly: TRUEでコンパイル済みのモデルを返す

• 推定のオプション– center: TRUEで説明変数を平均値で中心化する– slice: 単純効果をみるときのスライス変数を指定– offset: オフセット項わざを使うときの変数を指定

Page 45: rstanで簡単にGLMMができるglmmstan()を作ってみた

その他の引数• 並列化に関する引数– parallel: TRUEで並列化• ただし, Pglmmstan()を使うほうが楽

– cores:使用するコア数を指定する• デフォルトは chainsとおなじ

Page 46: rstanで簡単にGLMMができるglmmstan()を作ってみた

今日のお話• GLMMってやっぱほら,MCMCじゃない?

• glmmstan()という代筆関数を作った

• glmmstan()の使い方

• glmmstan()を使ってみた

Page 47: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmmstan()を使ってみる• 忘れたと思うのでもう一度– 2014年のプロ野球野手 140名の打撃成績と翌年の年俸

– プロ野球 Freakからダウンロードできる• http://baseball-freak.com/• (ただし,年俸のデータはWikipediaから集めた)

• 知りたいこと– ホームラン数はどういう分布でモデリングできる?– ホームラン一本打ったら,年俸はいくら増えるの?

Page 48: rstanで簡単にGLMMができるglmmstan()を作ってみた

ホームランの本数をモデリング• まずは度数分布を確認

・・・ポアソン分布?

Page 49: rstanで簡単にGLMMができるglmmstan()を作ってみた

glmmstanを使ってMCMC

• ホームラン数を予測するモデル–ポアソン分布を仮定

fit0 <- Pglmmstan(HR~1,dat,family="poisson",iter=5000)

でもどう考えても,プレイヤー差は無視できない

Page 50: rstanで簡単にGLMMができるglmmstan()を作ってみた

変量効果をいれて推定• プレイヤーの打力差をモデルに入れる–ポアソン分布を仮定–プレイヤーを変量効果として推定

fit1 <- Pglmmstan(HR~1+(1|player),dat, family="poisson",iter=5000)

アホみたいに改善された

ただし,このWAICは AICに比べてかなり小さい値なので,あってるか自信がない

Page 51: rstanで簡単にGLMMができるglmmstan()を作ってみた

年俸をホームラン数で予測したい

plot(dat$HR,dat$salary)

Page 52: rstanで簡単にGLMMができるglmmstan()を作ってみた

年俸の分布を見てみる

hist(dat$salary)

わ~,きれいな正規分布・・・なわけもなく

※100 万単位

↓ 阿部( 6億)

Page 53: rstanで簡単にGLMMができるglmmstan()を作ってみた

・・見なかったことにして線形回帰

fit2 <- Pglmmstan(salary~HR,dat)

AIC(lm(salary~HR,dat))

単純なモデルだと AICとほぼ一致

Page 54: rstanで簡単にGLMMができるglmmstan()を作ってみた

要約した結果を見る

output_result(fit2)$beta

ホームラン 1本打つと,平均 600 万年俸が増える!

※__sigmaはスケールパラメータで,線形回帰でいう残差分散です。   標準偏差ではありません。

Page 55: rstanで簡単にGLMMができるglmmstan()を作ってみた

年収って,対数正規分布らしい

Page 56: rstanで簡単にGLMMができるglmmstan()を作ってみた

OK,分布を変えよう• 対数正規分布を指定して,後は同じ–一般化線形モデル

fit3 <- Pglmmstan(salary~HR,dat,family="lognormal")

正規分布を仮定したモデル( 1660.6485)に比べて大幅に改善!

Page 57: rstanで簡単にGLMMができるglmmstan()を作ってみた

結果を見ると

HRが 10本から 11本に増えると・・・→ 約 410 万増!

HRが 20本から 21本に増えると・・・→ 約 760 万増!

でもまぁ, HRだけでは全然予測できない・・・

Output_result(fit3)$beta

Page 58: rstanで簡単にGLMMができるglmmstan()を作ってみた

球団によって違うんじゃね?• チーム( 12球団)を変量効果に入れて分析– →GLMM(一般化線形混合モデル)– HRの効果が球団によって違うかどうか

fit4 <- Pglmmstan(salary~HR+(1+HR|team),dat,

family = "lognormal",iter=5000)

多少改善された・・・?

Page 59: rstanで簡単にGLMMができるglmmstan()を作ってみた

MCMCが収束しているかを確認

output_stan(fit4)

Page 60: rstanで簡単にGLMMができるglmmstan()を作ってみた

結果の要約output_result(fit4)

※対数正規分布は対数リンクを使用

ホームランの係数 0.06に対して球団間変動は SDで0.017球団によって HRの効果が結構違いそう

Page 61: rstanで簡単にGLMMができるglmmstan()を作ってみた

shinystanかわいいよ shinystan

ソフトバンク→

阪神→広島→巨人→

金持ちの球団ほど効果が高い・・・ そりゃそうか

Page 62: rstanで簡単にGLMMができるglmmstan()を作ってみた

打率は?• 打率の程度によってどれくらい変わる?

fit5 <- Pglmmstan(salary~HR*AVG+(1+HR|team),dat,family="lognormal",center=T, slice="AVG",iter=5000)

ふむ。

※±1SDでスライス

Page 63: rstanで簡単にGLMMができるglmmstan()を作ってみた

打率が高い人と低い人の効果

ホームランと打率の交互作用効果はイマイチでも,一応打率の高さで HRの効果は変わっているようにみえる →打率が高い人が HR打つほうが年俸への効果は高そう 

output_result(fit5)$betaoutput_result(fit5)$simple

Page 64: rstanで簡単にGLMMができるglmmstan()を作ってみた

いろんな分布で遊んでみる• ガンマ分布–対数正規分布に似た分布–対数リンクで, 0より大きい実数をとる

fit6 <- Pglmmstan(salary~HR*AVG+(1+HR|team),dat,center=T,slice="AVG",

family=“gamma",iter=5000)

ふむ。やはり年俸は対数正規分布か。

Page 65: rstanで簡単にGLMMができるglmmstan()を作ってみた

まとめ• GLMMってやっぱほら,MCMCじゃない?– MCMCを使えば,複雑なモデルも同じ要領・アル

ゴリズムで推定できる–分布を超えてモデル比較ができる(らしい)

• glmmstan()を作ったよ–いま流行りの stanで自動的に GLMMしてくれる–まだまだ改良の余地があるので要望・間違いがあれば@simizu706までご連絡ください

Page 66: rstanで簡単にGLMMができるglmmstan()を作ってみた

Enjoy!

@simizu706http://norimune.net