glmmstanパッケージ
を作ってみた
2015年11月14日
SapporoR #5
@simizu706
自己紹介
• 清水裕士(@simizu706)
– 関西学院大学社会学部
• 専門
– 社会心理学
• 趣味
– 心理統計,統計ソフト開発
– 最近はstanとか
• Web:
– http://norimune.net
統計ソフトを作ってます
• Excelで動く心理統計用ソフト
– HAD
– 「HAD」でググると一番上に出てきます。
– norimune.net/had
注意
• 30分でスライド70枚超を疾走します
– Lightning Talk
• あとでスライドシェアにアップするので
それで確認してください
• ネットがつながる人はダウンロードして
みて,一度MCMCハァハァしてみてください
結論
• glmmstanパッケージを作った
– なんかいろんな線形モデルを簡単にMCMCで推定す
ることができるglmmstan関数が入っている
– githubにあげているので使ってみてください
– ただし,Rtoolsが必須なので事前に入れてください
• インストール方法
library(devtools)
install_github("norimune/glmmstan")
インストール方法2
proxyによってgithubに接続できない場合は以下のコードを実
行してください
library(devtools)
library(httr)
set_config(use_proxy(url="proxyのURL",
port=8080,
username = "ユーザーID",
password = "パスワード"))
install_github("norimune/glmmstan")
今日のRコード
• http://bit.ly/sapporor5
– にアップしています
– ネットがつながる人はダウンロードしてください
今日のお話
• いろんな統計モデルをベイズ推定したい
• glmmstanパッケージを作った
• glmmstanでベイズ推定してみた
• まとめ
今日のお話
• いろんな統計モデルをベイズ推定したい
• glmmstanパッケージを作った
• glmmstanでベイズ推定してみた
• まとめ
さて,ベイズ推定したい
• なぜベイズ推定なのか
– いろいろいいことがあるから
• 最小二乗法と比較して
– 複雑なモデルを推定できる
• 最尤法と比較して
– より複雑なモデルを推定できる
– 分散パラメータが不偏推定量になる
細かいことはいいから,
とにかくベイズ推定したい!
ベイズ推定といえばMCMC
• マルコフ連鎖モンテカルロ法
– パラメータの推定を乱数を用いたシミュレーション
で行う
細かいことはいいから,
とにかくMCMC推定したい!
RでのMCMCソフトウェア事情
• MCMCglmmパッケージ
– 比較的簡単にGLMMをMCMCできる
– 変量効果が複数あるとほぼ推定できない
• rBUGS
– コードを書けば,いろんなモデルを推定できる
– 相関が高い変量効果の推定では,いつまでたっても収束
しないという事態がある(らしい)
• rstanパッケージ
– 複雑な階層ベイズのモデルでも早く収束する
– NUTSという最新のMCMCアルゴリズムを使っている
stanかわいいよstan
• ベイズ推定(MCMC)用のフリーソフト
– R上からでもrstanパッケージをいれると動かせる
• rstanパッケージのインストール
– rstan2.7から簡単にインストールできる
– ただしRtoolsが必要
– install.packages(“rstan”)で可能
今日使うデータ
• 野球のデータ
– 2014年のプロ野球野手140名の打撃成績と翌年
の年俸
– プロ野球Freakからダウンロードできる
• http://baseball-freak.com/
• (ただし,年俸のデータはWikipediaから集めた)
• glmmstanパッケージに入っている
data(baseball)
ホームランの平均値を計算したい
• 普通に平均とかヒストグラムを出す
dat <- baseball
hist(dat$HR)
mean(dat$HR)
平均値をrstanで計算したい
• stanにおけるモデリング
– データが正規分布だと仮定(無茶は承知
data{
real HR[140];
}
parameters{
real<lower=0> m;
real<lower=0> s;
}
model{
HR ~ normal(m,s);
}
これぐらいなら簡単に書ける?
結果
plot(density(rstan::extract(fit)$m))
fit
でも正規分布じゃないじゃん?
hist(dat$HR)
m <- mean(rstan::extract(fit)$m)
s <- mean(rstan::extract(fit)$s)
y <- rnorm(140,m,s)
hist(y)
負の二項分布で平均値を計算
data{
int HR[140];
}
parameters{
real<lower=0> m;
real<lower=0> s;
}
model{
HR ~ neg_binomial_2(m,s);
}
負の二項分布
整数型
かなり近くなった
hist(dat$HR) m <- mean(extract(fit)$m)
s <- mean(extract(fit)$s)
y <- rnbinom(140,mu=m,size=1/s)
hist(y)
次は年俸をモデル化したい
• 年俸はsalaryに入ってる(単位は100万円)
これも正規分布じゃねぇな!
hist(dat$salary)
年俸をホームラン数で予測したい
年収って,対数正規分布らしい
ここでは簡単に対数変換
• ふむ,いい感じに正規分布っぽい
hist(log(dat$salary))
lmを使う場合
model <- lm(log(salary)~HR,data=dat)
plot(dat$HR,log(dat$salary))
abline(model)
対数年俸をホームランで予測
• HR1本打つと年俸はどれぐらい上がる?
data{
real salary[140];
real HR[140];
}
parameters{
real<lower=0> alpha;
real<lower=0> beta;
real<lower=0> s;
}
model{
real predict[140];
for(i in 1:140) predict[i] <- alpha+beta*HR[i];
salary ~ normal(predict,s);
}
お,おう,まだいけるかな・・
結果
plot(density(rstan::extract(fit3)$beta))
球団ごとでHRの効果が違う?
球団ごとに回帰直
線が違う・・・
傾きが球団で異な
るモデルを推定
球団によってHRの効果が違う
• 線形混合モデル
– データがクラスタでネストされていて,クラスタ内
に相関がある場合に使える
– あるいは,回帰モデルがクラスタによって違うこと
を考慮に入れられる
• 階層ベイズを使う
– 回帰係数自体が,正規分布に従うような階層的
なモデルを考える
階層ベイズのstanコード
data{
real salary[140];
real HR[140];
int team[140];
}
parameters{
real alpha;
real beta[12];
real gamma;
real<lower=0> s;
real<lower=0> tau;
}
model{
real predict[140];
for(j in 1:12) beta[j] ~ normal(gamma,tau);
for(i in 1:140) predict[i] <- alpha + beta[team[i]]*HR[i];
salary ~ normal(predict,s);
}
結果
回帰係数のチーム変動
plot(density(rstan::extract(fit4)$tau))
今日のお話
• いろんな統計モデルをベイズ推定したい
• glmmstanパッケージを作った
• glmmstanでベイズ推定してみた
• まとめ
ベイズ推定をstanでやりたい
• でもstanは初心者には敷居が高い
– データの読み込みとそれに対応した変数の宣言
など,慣れないとぱっとさっとはできない
• Rのコードだけ書いて,ぱぱっとベイズ推
定したい
– たとえば・・・glmer()と同じ書き方をしたらできる,
みたいな。
で,新しいパッケージを作った
• glmmstanパッケージを作った
– なんかいろんな線形モデルを簡単にMCMCで推
定することができるglmmstan関数が入っている
– githubにあげているので使ってみてください
• インストール方法
library(devtools)
install_github("norimune/glmmstan")
GLMMってなんだっけ
• Generalized Linear Mixed Modeling
– 一般化線形混合モデル
– 線形モデル+指数分布族+変量効果
• どういうときにGLMMを使うのか?
– データが離散分布に従うが,過分散が生じるとき
• 個体差が大きい場合
– データがネストされた構造になっていて,グルー
プごとに効果が異なるとき
みどり本のいつもの図
by 久保先生のWebから
GLMMができると・・
• 線形モデルは全部できる
– t検定,重回帰分析,ロジスティック回帰,ポアソン回
帰,一般化線形モデル,階層線形モデル,Mixedモデ
ル,一般化線形混合モデル
• glmmstanで遊んでみてください
– いろんなモデルをベイズ推定してみる
– 慣れてきたらstanコードを修正してみる
– ハマってきたらstanコードを自分で書いてみる
– 興奮してきたら新しい統計モデルを作ってみる
glmmstanの特徴
• モデルを書くとstanコードを自動生成
– lm()や,glm(),そしてlmer()と同じようにモデルを書け
ば,内部でstanコードを作成してstanを実効
• モデル式は~を使って書くのはlm()と同じ
– fit <- glmmstan(salary ~ HR, data=dat)
• 階層ベイズはlmer()と同じ文法で書く
– fit <- glmmstan(salary ~ HR+(1|team), data=dat)
glmmstanの特徴
• 全てのモデルでWAICを出力
– 最尤法におけるAICのMCMC版
– ただし,階層モデルの場合は局所パラメータを固
定効果として推定したWAICを出力
• このあたりはHijiyamaRで発表
• 比較的いろんな分布を扱える
– 正規分布以外に,離散,連続様々
使える分布とリンク関数
• 正規分布(”gaussian” or “normal”)
• ベルヌーイ分布(”bernoulli”)ロジットリンク
• 二項分布(”binomial”) ロジットリンク
• ポアソン分布(”poisson”) 対数リンク
• 負の二項分布(”nbinomial”) 対数リンク
• ガンマ分布(”gamma”) 対数リンク
• 対数正規分布(”lognormal”) 対数リンク
• ベータ分布(”beta”)ロジットリンク
• 順序カテゴリカル(”ordered”)ロジットリンク
備考
• リンク関数って?
– 予測値をデータの分布に合わせて変換するもの
• 基本は2種類
– 0未満にならない分布=対数リンク
• ポアソン,負の二項分布,ガンマ,対数正規分布・・
– 下限と上限が決まってる分布=ロジットリンク
• ベルヌーイ,二項分布,ベータ分布,順序・・
glmmstanの特徴
• 交互作用項と単純効果の分析
– 交互作用項があるとき,スライス変数を指定する
ことで単純効果の分析が可能
– 今のところ±1SDでスライス
• オフセット項を追加できる
– みどり本6章,「offset項わざ」を参照
– 今のところポアソンか負の二項分布のみ可
今日のお話
• いろんな統計モデルをベイズ推定したい
• glmmstanパッケージを作った
• glmmstanでベイズ推定してみた
• まとめ
まずは平均値を出してみたい
• 正規分布を仮定したホームランの平均値
– モデル式
• lm()形式。HR ~ 1で切片だけを推定ということ
• 正規分布の場合はfamilyは省略できる
library(glmmstan)
data(baseball)
dat <- baseball #ここではdatにいれなおしてる
fit0 <- glmmstan(HR~1,data=dat)
glmmstanを実行
• 並列化しないとき
– cores = 1を指定すると,並列化せず,チェインごとの
結果が表示される
– PCによっては並列化できないことがある
– その場合は,cores=1を加えること。
• 並列化するとき
– 何も指定しないと,自動的にstanは並列化する
(rstan2.7から)
– その場合は同時にチェインを走らせるので出力はシ
ンプル
出力1
• output_result()で要約を出力
※scaleとあるのは尺度パラメータ(残差分散)
出力2
• output_stan()でstanの結果を返す
– Rhatが1.05以下なら収束しているといわれている
※print()でも普通のstanの結果が出せるが,output_stan()
のほうが必要な結果を見られる
出力3
• MCMC要素を取り出すのはoutput_beta()
– 回帰係数と尺度パラメータのMCMC要素をデータ
フレーム型で返す
出力4
• こんな感じ
• MAP推定値が知りたい
– 分布の密度が最大の値が知りたい時もある
– そこで,map_mcmc()を用意してみた
beta <- output_beta(fit0)
plot(density(beta$Intercept))
出力5
• もちろん他のパッケージを使うこともで
きる
– ggmcmc
– shinystan
library(ggmcmc)
library(ggmcmc)
S <- ggs(fit0)
ggs_density(S,family="beta")
重回帰分析をしてみる
• 年俸をHRと三振で予測する
– 年俸をそのままモデルに投入
fit1 <- glmmstan(salary~HR+K,data=dat)
output_result(fit1)
分布を変えてみる
• 対数正規分布を使い,年俸を予測
– familyを変えるだけ
– リンク関数は,自動的に決まる
fit2 <- glmmstan(salary~HR+K,data=dat,
family="lognormal")
分布を変えてみる
• ポアソン分布でHRの平均値を推定
fit3 <- glmmstan(HR~1,data=dat,
family="poisson")
いろんなモデルを推定してみる
• 球団によって回帰係数が違うモデル
– 変量効果の指定
• ()を書いて,変量効果のモデルを指定
• |のあとにクラスタ変数を指定
• この場合,チームごとでHRの効果が違うモデルを推定
することを意味してる
fit4 <- glmmstan(salary~HR+K+(HR|team),
data=dat,
family="lognormal")
結果
いろんなモデルを推定してみる
• セリーグとパリーグで打率に差があるか
– 二項分布を使って,打率を推定+過分散を変量
効果で推定
– HITは安打数,ATbatsは打数
• これで打率を計算している
– (1|player)で選手ごとの打率を推定
fit5 <- glmmstan(cbind(HIT,ATbats-HIT)~
league+(1|player),
data=dat,
family="binomial")
結果
• リーグで打率に差はなさそう
– 若干セリーグのほうが高い
stanコードを修正して分析したい
• stanコードを指定すると優先的に分析
– stanコードだけを出力して,それを編集し,その
コードで分析ができる
code1 <- glmmstan(salary~HR+(1+HR|team),
data=dat,
family="lognormal",
codeonly = TRUE)
fit <- glmmstan(salary~HR+(1+HR|team),
data=dat,
family="lognormal",
stancode = code1)
その他の機能
• 交互作用項と単純効果の分析
fit7 <- glmmstan(salary~HR+K+HR:K+(HR|team),
data=dat,family="lognormal",
center=TRUE,
slice="K")
output_result(fit7)$simple
その他の機能
• オフセット項を追加できる
– 打席数に対するHRの割合の分布を検討したい
– 今のところポアソンか負の二項分布の場合のみ
※Log()をつけなくてもいい
fit8 <- glmmstan(HR~1+(1|player),
data=dat,
family="poisson",
offset="ATbats")
並列化処理
• stan2.7からデフォルトで並列化ができる
– なにもしなくても勝手に並列化する
• Pglmmstan()を使っても並列化できる
fit9 <- Pglmmstan(salary~HR+K+HR:K+(HR|team),
data=dat,
family="lognormal")
stanに関する引数
• MCMCについての引数
– iter:サンプリング回数 デフォルトは2000
– warmup:バーンイン期間 デフォルトはiterの半分
– chains:マルコフ連鎖の数 デフォルトは2
– thin:何回おきに採用するか デフォルトは1
• stanにいれる便利な引数
– stancode:いじったstanコードを入力する
– standata:いじったstanにいれるdataを入力する
– stanmodel:コンパイル済みのモデルを入力する
– stanfit:stanの出力を入力する(コンパイルを避ける)
その他の引数
• Stanに入れるためのオブジェクトを返す
– codeonly: TRUEでstanコードだけを返す
– dataonly: TRUEでstan用のデータだけを返す
– modelonly: TRUEでコンパイル済みのモデルを返す
• 推定のオプション
– center: TRUEで説明変数を平均値で中心化する
– slice: 単純効果をみるときのスライス変数を指定
– offset: オフセット項わざを使うときの変数を指定
その他の引数
• 並列化に関する引数
– parallel: TRUEで並列化
• ただし,Pglmmstan()を使うほうが楽
– cores:使用するコア数を指定する
• デフォルトはchainsとおなじ
おまけ
• HAD2glmmstan
– HADからglmmstanのコードを自動生成する機能
– HADとは・・・norimune.net/had
• データファイルも自動作成
– 事前にデータファイルを保存するフォルダを選択
しておく
• GUIでモデル選択をして実行
– するとglmmstan用のコードが出力される
フォルダの選択
• HAD2glmmstan設定ボタンを押す
HAD2glmmstan
出力
• 別シートにコードが出力
– コピーしてRに貼り付けて実行
インストール用のコードも生成
Enjoy!
@simizu706
http://norimune.net

glmmstanパッケージを作ってみた