compose_data
を使ってモデル用のデータフレームを準備するspread_draws
を使ってフィットからドローをtidyフォーマットで抽出する
point_interval
関数で点の要約と間隔を指定する中央値|平均値|モード][qi|hdi]`.
{#point-summaries-and-intervals-with-the-point_interval-functions-[median|mean|mode][qi|hdi]}
gather_draws
と gather_variables
であるこの vignette は、Rのベイズモデルでtidyデータ (1行に1つの観測値)
の使用を容易にする tidybayes
パッケージを紹介する。この
vignette
は、JAGSやStanなどの汎用モデリング関数でtidyデータを使用することに向けられたものである。brms
や rstanarm
のような高レベルのモデリング関数での
tidybayes
の使用に関する同様の紹介は、vignette("tidy-brms")
や
vignette("tidy-rstanarm")
を参照。
また、このビネットは、以下のような使用方法を説明している。
ggdist
( の姉妹パッケージ)
を使ってモデル出力を可視化することができる。 tidybayes
JAGS
や Stan などの一般的なモデリング関数のデフォルトの出力
(場合によっては入力) データ形式は、 tidy data
の理想に全く合致していないことがよくある。例えば、入力形式は、データフレームの代わりにリストを期待し、すべての変数が数値としてエンコードされることを期待する
(因子を数値に変換し、因子ごとのレベルの数またはデータフレーム内の観察数を格納するためにインデックス変数を作成することが必要)
。出力形式は多くの場合、行列形式であり
(ggplotのようなライブラリで使用するために変換が必要)
、数値インデックスを使用する
(意味のあるラベルを付けたプロットや表を作成したい場合、因子レベルの名前に戻す変換が必要)
。tidybayes
はこの種のタスクをすべて自動化している。
tidybayes
APIには、使い勝手を良くするための核となる考え方がいくつかある。
整頓されたデータとは、必ずしもすべてのパラメータ名を値とすることではない__。ggmcmc
ライブラリ (モデルの結果を Parameter
と value
の列を持つデータフレームに変換する) とは対照的に、tidybayes
の spread_draws
関数は、列の名前がパラメータと
(場合によっては)
それらのパラメータのインデックスであるデータフレームを、できるだけ自動的に、モデルの言語でそれらの変数を参照する方法とできるだけ同じ構文で作成する。ggmcmc
のアプローチと同様の関数が gather_draws
でも提供されている。のようなインデックスを持つパラメータを、データフレームをどのように見せるか、という面倒な作業を
tidybayes
が行ってくれることが目的である。
"b [1,2] "
などのインデックスを持つパラメータを整頓されたデータに変換することも含めて、データフレームを必要な形にする面倒な作業を行うことである。
Fit into the tidyverse. tidybayes
メソッドは tidyverse
( dplyr
,
tidyr
, ggplot2
, etc)
のユーザーに馴染みのあるワークフローにフィットする。つまり、パイプ (
%>%
)
のワークフローにフィットし、グループ化されたデータフレームを使用し尊重し
(したがって spread_draws
と gather_draws
はすでに変数インデックスでグループ化された結果を返し、median_qi
などのメソッドは変数とグループの点要約と間隔を同時に計算する)
、もし既存の tidyverse
パッケージが提供する関数によってすでに容易になっているのなら
(それが共通のイディオムにずっと明確なコードになっていなければ)
車輪をあまり再発明しないようにすることである。他のパッケージの列名
(例えば broom::tidy
)
との互換性のために、tidybayes
は
to_broom_names
のような変換関数を提供し、データ変換パイプラインに直接ドロップすることができる。
一枚岩のプロットや操作ではなく、組み合わせ可能な操作やプロットプリミティブに重点を置く__。他のいくつかのパッケージ(特に
bayesplot
と ggmcmc
)は、ベイズの結果をプロットするための優れた様々な既成のメソッドを既に提供している。tidybayes
は、この関数を複製することは避けている。その代わりに、ベイズサンプルの生成と操作を整然としたデータ形式で行うための複合操作と、カスタムプロットを簡単に作成できる
ggplot
用のグラフィカルプリミティブを提供することに焦点を合わせている。最も簡単には、bayesplot
と ggmcmc
が完全な ggplot
オブジェクトを返す多くのオプションを持つ関数を持つ傾向があるのに対し、tidybayes
は独自のカスタムプロットに合成し組み合わせることができるプリミティブを提供する傾向がある
( geom
のような)。私はどちらのアプローチにもその場所があると信じている:
既製の関数は、(多くの診断プロットのように)
カスタマイズを必要としない一般的で迅速な操作に特に有用であり、一方
composable 操作は ( my
opinion で)
より複雑なカスタムプロットにとって有用である傾向がある。
しかし、オプション (と、そもそもデータが整頓されていること) を使えば、必要なときに簡単に独自の道を進むことができる。
モデル内の変数名は、暗号ではなく、説明的であるべきです__。この原則は、暗号のような
(短い) 添え字を避け、より長い (しかし説明的な)
添え字を使用することを意味する。これは、モデルの読みやすさとアクセスしやすさの問題である。例えば、Stanユーザーの間で
(そしてStanのマニュアルでも) よくあるパターンは、グループ内の要素の数
(例えば、参加者の数) を参照するために J
のような変数を使い、そのグループ内の特定の要素を参照するために
j
のような対応するインデックスを使うことである。私は、n_participant
のようなパターンがグループのサイズ、participant
(または
p
のようなニーモニックな短縮形)
が特定の要素に適していると思っている。名前が自動生成される関数 (
compose_data
など) では、tidybayes
は
(デフォルトで)
あなたがこのようなより説明的な名前を望んでいると仮定する。しかし、あなたはいつでもデフォルトの命名方式をオーバーライドすることができる。
tidybayes
は、統一されたインターフェースで様々なモデルをサポートすることを目的としている。現在、対応している機種は以下の通りである。
rstan 、 cmdstanr 、 brms 、 rstanarm 、 runjags 、 rjags 、 jagsUI 、 coda::mcmc and
coda::mcmc.list 、 posterior::draws 、 MCMCglmm 。
と、独自の as.mcmc.list
の実装を持つものである。 tidybayes.rethinking
パッケージをインストールすると、 rethinking
パッケージのモデルもサポートされる。
最新の対応モデル一覧は、?"tidybayes-models"
を参照。
このvignetteを実行するには、以下のライブラリが必要である。
library(magrittr)
library(dplyr)
library(forcats)
library(modelr)
library(ggdist)
library(tidybayes)
library(ggplot2)
library(cowplot)
library(emmeans)
library(broom)
library(rstan)
library(rstanarm)
library(brms)
library(bayesplot)
library(MCMCglmm)
library(RColorBrewer)
theme_set(theme_tidybayes() + panel_border())
これらのオプションは、Stanの動作を高速化するためのものである。
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectCores())
tidybayes
を実証するために、5つの条件からそれぞれ10個のオブザベーションを持つ単純なデータセットを使用することにする。
set.seed(5)
= 10
n = 5
n_condition =
ABC tibble(
condition = rep(c("A","B","C","D","E"), n),
response = rnorm(n * 5, c(0,1,2,1,-1), 0.5)
)
データのスナップショットはこのような感じである。
head(ABC, 10)
condition | response |
---|---|
A | -0.4204277 |
B | 1.6921797 |
C | 1.3722541 |
D | 1.0350714 |
E | -0.1442796 |
A | -0.3014540 |
B | 0.7639168 |
C | 1.6823143 |
D | 0.8571132 |
E | -0.9309459 |
これは典型的な整頓されたフォーマットのデータフレームです: 1行に1つの観測値である。グラフィカルに
%>%
ABC ggplot(aes(x = response, y = fct_rev(condition))) +
geom_point(alpha = 0.5) +
ylab("condition")
compose_data
を使ってモデル用のデータフレームを準備するデータフレームから JAGS や Stan
などのサンプラーで利用可能な形式にデータを移行する場合、演算回数や因子のレベル数
を格納するインデックス変数の生成など、一連の面倒な操作が必要になる。compose_data
は、これらの操作を自動化するものである。
この例のデータを階層モデルにすると、条件全体の平均値(
overall_mean
)、条件平均値の標準偏差(
condition_mean_sd
)、各条件内の平均値(
condition_mean [condition]
)、条件内平均(
response_sd
)、条件内平均が与えられたときの回答の標準偏差(
)が当てはまる。
data {
int<lower=1> n;
int<lower=1> n_condition;
int<lower=1, upper=n_condition> condition[n];
real response[n];
}parameters {
real overall_mean;
vector[n_condition] condition_zoffset;
real<lower=0> response_sd;
real<lower=0> condition_mean_sd;
}transformed parameters {
vector[n_condition] condition_mean;
condition_mean = overall_mean + condition_zoffset * condition_mean_sd;
}model {
0, 1); // => half-cauchy(0, 1)
response_sd ~ cauchy(0, 1); // => half-cauchy(0, 1)
condition_mean_sd ~ cauchy(0, 5);
overall_mean ~ normal(0, 1); // => condition_mean ~ normal(overall_mean, condition_mean_sd)
condition_zoffset ~ normal(for (i in 1:n) {
response[i] ~ normal(condition_mean[condition[i]], response_sd);
} }
このモデルをコンパイルして、変数 ABC_stan
にロードしている。
このモデルは、これらの変数を入力として想定している。
n
: 観察数n_condition
: 条件数condition
: 各観測の状態を示す整数のベクタresponse
: 観察結果のベクトル私たちのデータフレーム ( ABC
) には
response
と condition
しかなく、condition
は間違った形式である
(数値ではなく係数)。しかし、compose_data
は、上記の変数を正しい形式で含むリストを自動的に生成することができる。それは、condition
が因子であることを認識し、それを数値に変換し、condition
のレベルの数を含む n_condition
変数を自動的に追加し、観測数
(データフレーム内の行数) を含む n
列を追加する。
compose_data(ABC)
## $condition
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
##
## $n_condition
## [1] 5
##
## $response
## [1] -0.42042774 1.69217967 1.37225407 1.03507138 -0.14427956 -0.30145399 0.76391681 1.68231434 0.85711318
## [10] -0.93094589 0.61381517 0.59911027 1.45980370 0.92123282 -1.53588002 -0.06949307 0.70134345 0.90801662
## [19] 1.12040863 -1.12967770 0.45025597 1.47093470 2.73398095 1.35338054 -0.59049553 -0.14674092 1.70929454
## [28] 2.74938691 0.67145895 -1.42639772 0.15795752 1.55484708 3.10773029 1.60855182 -0.26038911 0.47578692
## [37] 0.49523368 0.99976363 0.11890706 -1.07130406 0.77503018 0.59878841 1.96271054 1.94783398 -1.22828447
## [46] 0.28111168 0.55649574 1.76987771 0.63783576 -1.03460558
##
## $n
## [1] 50
このため、自分でデータを加工することなく、すぐにモデルの実行に移れる。
= sampling(ABC_stan, data = compose_data(ABC), control = list(adapt_delta = 0.99)) m
結果はこのようになる。
m
## Inference for Stan model: 150269bbfe815db848542eb814742386.
## 4 chains, each with iter=2000; warmup=1000; thin=1;
## post-warmup draws per chain=1000, total post-warmup draws=4000.
##
## mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
## overall_mean 0.61 0.03 0.68 -0.69 0.28 0.62 0.97 1.81 508 1.01
## condition_zoffset[1] -0.39 0.02 0.50 -1.41 -0.72 -0.39 -0.06 0.57 777 1.00
## condition_zoffset[2] 0.34 0.02 0.49 -0.59 0.02 0.35 0.66 1.33 888 1.01
## condition_zoffset[3] 1.11 0.02 0.58 0.01 0.70 1.10 1.48 2.26 865 1.01
## condition_zoffset[4] 0.36 0.02 0.49 -0.61 0.04 0.36 0.69 1.32 872 1.01
## condition_zoffset[5] -1.39 0.03 0.68 -2.78 -1.84 -1.35 -0.93 -0.12 681 1.01
## response_sd 0.56 0.00 0.06 0.46 0.52 0.56 0.60 0.70 1606 1.00
## condition_mean_sd 1.25 0.02 0.55 0.61 0.89 1.12 1.43 2.71 546 1.01
## condition_mean[1] 0.19 0.00 0.18 -0.16 0.07 0.19 0.31 0.55 4294 1.00
## condition_mean[2] 1.00 0.00 0.18 0.65 0.89 1.00 1.12 1.34 4700 1.00
## condition_mean[3] 1.84 0.00 0.18 1.48 1.71 1.84 1.96 2.19 4735 1.00
## condition_mean[4] 1.02 0.00 0.17 0.66 0.90 1.02 1.13 1.35 4398 1.00
## condition_mean[5] -0.89 0.00 0.18 -1.24 -1.01 -0.89 -0.77 -0.54 4297 1.00
## lp__ 0.28 0.09 2.45 -5.51 -1.14 0.65 2.06 3.97 752 1.00
##
## Samples were drawn using NUTS(diag_e) at Thu Dec 15 15:49:45 2022.
## For each parameter, n_eff is a crude measure of effective sample size,
## and Rhat is the potential scale reduction factor on split chains (at
## convergence, Rhat=1).
spread_draws
を使ってフィットからドローをtidyフォーマットで抽出するさて、結果が出たところで、お楽しみは、ドローを整頓されたフォーマットで取り出すことである!モデルからドローを抽出するためのStanのデフォルトのメソッドは、ネストされたフォーマットでそれを行う。
str(rstan::extract(m))
## List of 6
## $ overall_mean : num [1:4000(1d)] 1.057 2.369 -1.134 -0.295 0.106 ...
## ..- attr(*, "dimnames")=List of 1
## .. ..$ iterations: NULL
## $ condition_zoffset: num [1:4000, 1:5] -0.5102 -1.0016 0.7883 0.2327 0.0647 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ iterations: NULL
## .. ..$ : NULL
## $ response_sd : num [1:4000(1d)] 0.566 0.518 0.478 0.57 0.535 ...
## ..- attr(*, "dimnames")=List of 1
## .. ..$ iterations: NULL
## $ condition_mean_sd: num [1:4000(1d)] 1.66 2.46 1.5 1.62 2.38 ...
## ..- attr(*, "dimnames")=List of 1
## .. ..$ iterations: NULL
## $ condition_mean : num [1:4000, 1:5] 0.2085 -0.0992 0.0492 0.082 0.2603 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ iterations: NULL
## .. ..$ : NULL
## $ lp__ : num [1:4000(1d)] 1.16 -2.464 -0.129 2.318 3.953 ...
## ..- attr(*, "dimnames")=List of 1
## .. ..$ iterations: NULL
また、Stanではドローをマトリクスやデータフレームとして抽出する方法がある (JAGSやMCMCglmmなど他のモデルタイプでは、独自のフォーマットがある) 。
spread_draws
メソッドは、tidybayes
がサポートするすべてのモデルタイプに共通の形式をもたらする。.chain
と .iteration
の列が各行のチェーンとイテレーションを格納し
(利用可能な場合) 、.draw
の列が各ドローにユニークなインデックスを付け、残りの列がモデル変数または変数インデックスに対応する。spread_draws
メソッドは、変数の名前と変数インデックスの名前を含むことができる、任意の数の列の指定を受け入れる。例えば、condition_mean
変数を整然としたデータフレームとして抽出し、その最初の (そして唯一の)
インデックスの値を condition
列に入れることができる。この構文は、モデル自体で
condition_mean
変数のインデックスを指定する方法と直接エコーするものである。
%>%
m spread_draws(condition_mean[condition]) %>%
head(10)
## Warning: `gather_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `gather()` instead.
## ℹ The deprecated feature was likely used in the tidybayes package.
## Please report the issue at <]8;;https://github.com/mjskay/tidybayes/issues/newhttps://github.com/mjskay/tidybayes/issues/new]8;;>.
condition | condition_mean | .chain | .iteration | .draw |
---|---|---|---|---|
1 | 0.0425315 | 1 | 1 | 1 |
1 | 0.4303988 | 1 | 2 | 2 |
1 | 0.0148958 | 1 | 3 | 3 |
1 | 0.5342393 | 1 | 4 | 4 |
1 | 0.2983696 | 1 | 5 | 5 |
1 | 0.0502674 | 1 | 6 | 6 |
1 | 0.1020039 | 1 | 7 | 7 |
1 | 0.1701838 | 1 | 8 | 8 |
1 | 0.0351719 | 1 | 9 | 9 |
1 | 0.2785180 | 1 | 10 | 10 |
そのままでは、結果として得られる変数は、そのインデックスがどこから来たのかについて何も知らない。condition_mean
変数のインデックスはもともと ABC
データフレーム内の
condition
因子から派生したものである。しかし、Stanはこのことを知らない:Stanにとっては単なる数値インデックスなので、condition
列には、これらの数値が対応する因子レベル ( 1, 2, 3, 4, 5
)
ではなく、ただ数値 ( )
が含まれている。"A "," B "," C "," D "," E"
).
spread_draws
を使う前に recover_types
を通してモデルを渡すことで、この失われた型情報を回復することができる。recover_types
はモデルのコピーに、渡されたデータフレーム (または他のオブジェクト)
の型情報を格納する属性を追加して返すだけである。これだけでは何の役にも立ちないが、spread_draws
のような関数はこの情報を使って、任意の列やインデックスを元のデータフレーム内の同じ名前を持つ列のデータ型に変換して戻する。この例では、spread_draws
は、condition
列が5つのレベルを持つ因子であることを認識する
( "A "," B "," C "," D "," E"
)であることを認識し、自動的に因子に変換する。
%>%
m recover_types(ABC) %>%
spread_draws(condition_mean[condition]) %>%
head(10)
condition | condition_mean | .chain | .iteration | .draw |
---|---|---|---|---|
A | 0.0425315 | 1 | 1 | 1 |
A | 0.4303988 | 1 | 2 | 2 |
A | 0.0148958 | 1 | 3 | 3 |
A | 0.5342393 | 1 | 4 | 4 |
A | 0.2983696 | 1 | 5 | 5 |
A | 0.0502674 | 1 | 6 | 6 |
A | 0.1020039 | 1 | 7 | 7 |
A | 0.1701838 | 1 | 8 | 8 |
A | 0.0351719 | 1 | 9 | 9 |
A | 0.2785180 | 1 | 10 | 10 |
spread_draws
を複数回に分けて呼び出したいことがよくあるので、元のモデルが適合された直後に
recover_types
を使って装飾すると、一回だけ呼び出せばよいので便利である。
%<>% recover_types(ABC) m
これで、以降の spread_draws
の呼び出しの前に、recover_types
の呼び出しを省略することができるようになった。
point_interval
関数で点の要約と間隔を指定する中央値|平均値|モード][qi|hdi]`.
{#point-summaries-and-intervals-with-the-point_interval-functions-[median|mean|mode][qi|hdi]}tidybayes
は、描画から点の要約や区間を整然としたフォーマットで生成するための関数群を提供する。これらの関数は、
[median|mean|mode] _ [qi|hdi]
の命名規則に従っている。例えば、median_qi
,
mean_qi
, mode_hdi
, などである。最初の名前 (
_
の前)
は点要約のタイプを示し、2番目の名前は区間のタイプを示す。qi
は分位数区間 (別名:等値尾区間、中心区間、パーセンタイル区間)
を、hdi
は最高密度区間を出力する。カスタム点または区間関数は、point_interval
関数を使用して適用することもできる。
例えば、オブザベーションの全体的な平均と標準偏差に対応するドローを抽出することができる。
%>%
m spread_draws(overall_mean, response_sd) %>%
head(10)
.chain | .iteration | .draw | overall_mean | response_sd |
---|---|---|---|---|
1 | 1 | 1 | 0.4720119 | 0.5490346 |
1 | 2 | 2 | 0.7776089 | 0.5470606 |
1 | 3 | 3 | -0.1013847 | 0.5573434 |
1 | 4 | 4 | -0.0086601 | 0.6155352 |
1 | 5 | 5 | 0.3126983 | 0.6161216 |
1 | 6 | 6 | 0.3534224 | 0.5174635 |
1 | 7 | 7 | -0.1594659 | 0.4984251 |
1 | 8 | 8 | 1.4268865 | 0.5383222 |
1 | 9 | 9 | 1.9375415 | 0.5635136 |
1 | 10 | 10 | 1.3272984 | 0.5369298 |
condition_mean [condition]
と同様、整頓されたデータフレームが得られる。変数の中央値と95%分位間隔が欲しい場合は、median_qi
を適用する。
%>%
m spread_draws(overall_mean, response_sd) %>%
median_qi(overall_mean, response_sd)
overall_mean | overall_mean.lower | overall_mean.upper | response_sd | response_sd.lower | response_sd.upper | .width | .point | .interval |
---|---|---|---|---|---|---|---|---|
0.6177286 | -0.6883475 | 1.80586 | 0.5564333 | 0.4580972 | 0.702512 | 0.95 | median | qi |
median_qi
は、各入力列をその中央値を用いて要約する。要約する列が複数ある場合、
%区間の境界に対応する と 列 (各列 )
がそれぞれ作成される。列が1つしかない場合、 と
という名前が区間境界に使用される。 .width
x.lower
x.upper
x
.lower
.upper
上記のように、中央値と区間を取得したい列を指定することができるが、列のリストを省略すると、median_qi
は、グループ化列や特殊列ではないすべての列 ( .chain
,
.iteration
, または .draw
のような)
を使用する。したがって、上記の例では、overall_mean
と
response_sd
は、モデルから収集した唯一の列でもあるため、median_qi
の冗長な引数となっている。から、前のコードを次のように単純化することができる。
%>%
m spread_draws(overall_mean, response_sd) %>%
median_qi()
overall_mean | overall_mean.lower | overall_mean.upper | response_sd | response_sd.lower | response_sd.upper | .width | .point | .interval |
---|---|---|---|---|---|---|---|---|
0.6177286 | -0.6883475 | 1.80586 | 0.5564333 | 0.4580972 | 0.702512 | 0.95 | median | qi |
condition_mean
のように1つ以上のインデックスを持つ変数がある場合、前と同様に
median_qi
(または point_interval
ファミリーの他の関数) を適用することができる。
%>%
m spread_draws(condition_mean[condition]) %>%
median_qi()
condition | condition_mean | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi |
B | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi |
C | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi |
D | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi |
E | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi |
median_qi
はどのようにして集約するものを知ったのだろうか?
spread_draws
によって返されたデータフレームは、あなたが渡したすべてのインデックス変数によって自動的にグループ化される。この場合、それは
condition
によってグループ化されることを意味する。median_qi
はグループを尊重し、すべてのグループ内のポイントの要約と間隔を計算する。そして、median_qi
に列が渡されなかったので、唯一の非特殊列 ( .
-prefixed)
であり、非グループ列である condition_mean
に対して処理を行う。したがって、上記の短縮された構文は、より冗長なこの呼び出しと等価である。
%>%
m spread_draws(condition_mean[condition]) %>%
group_by(condition) %>% # this line not necessary (done automatically by spread_draws)
median_qi(condition_mean)
condition | condition_mean | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi |
B | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi |
C | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi |
D | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi |
E | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi |
1列しか与えられない場合、median_qi
は区間の下端と上端にそれぞれ .lower
と .upper
という名前を使用する。
tidybayes
は、 の実装も提供している。
posterior::summarise_draws()
グループ化されたデータフレーム
( tidybayes::summaries_draws.grouped_df()
)
を作成することができる。
を使用すると、コンバージェンス診断が迅速に行える。
%>%
m spread_draws(condition_mean[condition]) %>%
summarise_draws()
condition | variable | mean | median | sd | mad | q5 | q95 | rhat | ess_bulk | ess_tail |
---|---|---|---|---|---|---|---|---|---|---|
A | condition_mean | 0.1941861 | 0.1923963 | 0.1803730 | 0.1795563 | -0.0997071 | 0.4963313 | 1.000495 | 4351.924 | 2942.437 |
B | condition_mean | 1.0000573 | 1.0007694 | 0.1758305 | 0.1706891 | 0.7145377 | 1.2846996 | 1.000052 | 4734.204 | 3041.213 |
C | condition_mean | 1.8369746 | 1.8382099 | 0.1810089 | 0.1802728 | 1.5394096 | 2.1299333 | 1.000210 | 4748.792 | 3486.504 |
D | condition_mean | 1.0168191 | 1.0180656 | 0.1735925 | 0.1730640 | 0.7296146 | 1.2970612 | 1.001107 | 4421.551 | 3420.011 |
E | condition_mean | -0.8899228 | -0.8904054 | 0.1759922 | 0.1760503 | -1.1813634 | -0.5975538 | 1.000152 | 4330.823 | 3349.994 |
中央値と区間のプロットは、ggdist::geom_pointinterval()
または ggdist::stat_pointinterval()
を使えば簡単である。これは ggplot2::geom_pointrange()
と似ているが、複数の区間に対して賢明なデフォルトが設定されている。たとえば
%>%
m spread_draws(condition_mean[condition]) %>%
ggplot(aes(y = fct_rev(condition), x = condition_mean)) +
stat_pointinterval()
## Warning: Using the `size` aesthietic with geom_segment was deprecated in ggplot2 3.4.0.
## ℹ Please use the `linewidth` aesthetic instead.
これらの関数はデフォルトで .width = c(.66, .95)
を持つが
(66%および95%区間を表示) 、これは
ggdist::stat_pointinterval()
に .width
引数を渡すことで変更可能である。
ggdist::stat_halfeye()
geomは、「半眼プロット」
(区間と密度の組み合わせ)
を生成するためのショートカットを提供する。この例は、区間確率を変更する方法も示している
(ここでは、90%および50%区間に変更) 。
%>%
m spread_draws(condition_mean[condition]) %>%
ggplot(aes(y = fct_rev(condition), x = condition_mean)) +
stat_halfeye(.width = c(.90, .5))
あるいは、密度の一部をカラーでアノテートしたいとする。fill
の美観は、ggdist::stat_halfeye()
を含む
ggdist::geom_slabinterval()
ファミリーのすべてのジオムおよび統計において、スラブ内で変化させることができる。例えば、ドメイン固有のROPE
(region of practical equivalence)
をアノテーションしたい場合、次のようなことが可能である。
%>%
m spread_draws(condition_mean[condition]) %>%
ggplot(aes(y = fct_rev(condition), x = condition_mean, fill = stat(abs(x) < .8))) +
stat_halfeye() +
geom_vline(xintercept = c(-.8, .8), linetype = "dashed") +
scale_fill_manual(values = c("gray80", "skyblue"))
## Warning: `stat(abs(x) < 0.8)` was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(abs(x) < 0.8)` instead.
stat_slabinterval
分布を視覚化するための様々な追加統計が
ggdist::geom_slabinterval()
ファミリーの統計とジオムで提供されている。
を参照。 vignette("slabinterval ", package =" ggdist")
を参照。
.width =
引数プロットする前にデータを要約したい場合
(以下のような場合に便利である。 large samples)、median_qi()
とその姉妹関数も生成することができる。
引数 .width =
を設定することにより、任意の数の確率区間を設定することができる。
%>%
m spread_draws(condition_mean[condition]) %>%
median_qi(.width = c(.95, .8, .5))
condition | condition_mean | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi |
B | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi |
C | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi |
D | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi |
E | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi |
A | 0.1923963 | -0.0329867 | 0.4267323 | 0.80 | median | qi |
B | 1.0007694 | 0.7753011 | 1.2225014 | 0.80 | median | qi |
C | 1.8382099 | 1.6050739 | 2.0721056 | 0.80 | median | qi |
D | 1.0180656 | 0.7954088 | 1.2386680 | 0.80 | median | qi |
E | -0.8904054 | -1.1131385 | -0.6652568 | 0.80 | median | qi |
A | 0.1923963 | 0.0736693 | 0.3141231 | 0.50 | median | qi |
B | 1.0007694 | 0.8863465 | 1.1165120 | 0.50 | median | qi |
C | 1.8382099 | 1.7139749 | 1.9584869 | 0.50 | median | qi |
D | 1.0180656 | 0.9012443 | 1.1341256 | 0.50 | median | qi |
E | -0.8904054 | -1.0090758 | -0.7716409 | 0.50 | median | qi |
結果は整然とした形式で、インデックス( condition
)と確率水準( .width
)ごとに1行ずつ表示される。これはプロットを容易にする。たとえば、-.width
を size
の美観に割り当てると、すべての区間が表示され、太い線がより小さい区間に対応するようになる。
%>%
m spread_draws(condition_mean[condition]) %>%
median_qi(.width = c(.95, .66)) %>%
ggplot(aes(
y = fct_rev(condition), x = condition_mean, xmin = .lower, xmax = .upper,
# size = -.width means smaller probability interval => thicker line
# this can be omitted, geom_pointinterval includes it automatically
# if a .width column is in the input data.
size = -.width
+
)) geom_pointinterval()
ggdist::geom_pointinterval()
が含まれている。
size = -.width
をデフォルトの美的マッピングとして使用することで、まさにこの使い方を容易にすることができる。
アルファレベルがたまたまあなたが行おうとしている決定と一致する場合、区間は良いが、事後的な形状を得ることはより良いことである (したがって、上記の目のプロット) 。一方、密度プロットから推論するのは不正確である (ある形状の面積を別の形状の割合で推定するのは難しい知覚的作業である) 。頻度形式での確率の推論はより簡単で、 quantile dotplots ( Kay et al. 2016, Fernandes et al. 2018)の動機となった。これは任意の間隔 (プロットのドット解像度まで、下の例では100) を正確に推定することも可能である。
tidybayes のジオムの slabinterval ファミリーには dots
と
dotsinterval
ファミリーがあり、ドットプロットの適切なビンサイズを自動的に決定し、サンプルから分位を計算して分位ドットプロットを構築できる。ggdist::stat_dots()
はサンプルに使用するために設計されたバリアントである。
%>%
m spread_draws(condition_mean[condition]) %>%
ggplot(aes(x = condition_mean, y = fct_rev(condition))) +
stat_dotsinterval(quantiles = 100)
このアイデアは、事後を1つの標準的な点または区間として考えるのではなく、 (例えば) 100のほぼ等しい可能性のある点として表現することである。
point_interval()
関数ファミリーは、以下の命名規則に従っている。
[median|mean|mode] _ [qi|hdi|hdci]
median_qi()
これらは、一連の名前 (または列で計算された式) を取り、対応する点要約関数
(中央値、平均値、最頻値) と区間 (qi、hdi、またはhdci)
でこれらの列を要約する。 qi
は分位数区間
(別名:等値尾区間、中心区間、パーセンタイル区間) を、hdi
は1つ以上の最高 (事後) 密度区間を、hdci
は単一の (おそらく)
最高密度連続区間をそれぞれ出力する。これらは、任意の組み合わせで使用することができる。
*_hdi
関数には、さらに違いがある。多峰性分布の場合、各確率レベルに対して複数の区間を返すかもしれない。以下は、多峰性正規混合分布からのいくつかの抽選である。
set.seed(123)
= tibble(
multimodal_draws x = c(rnorm(5000, 0, 1), rnorm(2500, 4, 1))
)
mode_hdi()
を通すと、80%の確率レベルで複数の区間が得られる。
%>%
multimodal_draws mode_hdi(x, .width = .80)
x | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|
-0.0152584 | -1.523224 | 1.598902 | 0.8 | mode | hdi |
-0.0152584 | 3.043151 | 4.997135 | 0.8 | mode | hdi |
これは、プロットするとわかりやすいね。
%>%
multimodal_draws ggplot(aes(x = x)) +
stat_slab(aes(y = 0)) +
stat_pointinterval(aes(y = -0.5), point_interval = median_qi, .width = c(.95, .80)) +
annotate("text", label = "median, 80% and 95% quantile intervals", x = 6, y = -0.5, hjust = 0, vjust = 0.3) +
stat_pointinterval(aes(y = -0.25), point_interval = mode_hdi, .width = c(.95, .80)) +
annotate("text", label = "mode, 80% and 95% highest-density intervals", x = 6, y = -0.25, hjust = 0, vjust = 0.3) +
xlim(-3.25, 18) +
scale_y_continuous(breaks = NULL)
spread_draws()
は、異なるインデックスを持つ変数の抽出をサポートしている。同じ名前のインデックスを自動的にマッチングし、必要に応じて値を複製して、すべてのインデックスのレベルの組み合わせごとに1つの行を生成する。例えば、各条件の平均と全体の平均の差を計算したい場合がある。そのためには、全体の平均とすべての条件の平均から描画を抽出することができる。
%>%
m spread_draws(overall_mean, condition_mean[condition]) %>%
head(10)
.chain | .iteration | .draw | overall_mean | condition | condition_mean |
---|---|---|---|---|---|
1 | 1 | 1 | 0.4720119 | A | 0.0425315 |
1 | 1 | 1 | 0.4720119 | B | 0.7921493 |
1 | 1 | 1 | 0.4720119 | C | 1.4227343 |
1 | 1 | 1 | 0.4720119 | D | 0.9238246 |
1 | 1 | 1 | 0.4720119 | E | -0.7925493 |
1 | 2 | 2 | 0.7776089 | A | 0.4303988 |
1 | 2 | 2 | 0.7776089 | B | 0.8152688 |
1 | 2 | 2 | 0.7776089 | C | 1.6948455 |
1 | 2 | 2 | 0.7776089 | D | 1.0371610 |
1 | 2 | 2 | 0.7776089 | E | -0.7596942 |
各抽選の中で、condition_mean
の各インデックスに対応するように overall_mean
が繰り返される。したがって、dplyr::mutate()
関数を用いてすべての行の差分をとり、median_qi()
で要約することができる。
%>%
m spread_draws(overall_mean, condition_mean[condition]) %>%
mutate(condition_offset = condition_mean - overall_mean) %>%
median_qi(condition_offset)
condition | condition_offset | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A | -0.4129033 | -1.6453950 | 0.9101742 | 0.95 | median | qi |
B | 0.3879801 | -0.7981041 | 1.6785521 | 0.95 | median | qi |
C | 1.2143535 | 0.0143735 | 2.5476898 | 0.95 | median | qi |
D | 0.4014766 | -0.8057669 | 1.7446861 | 0.95 | median | qi |
E | -1.5085301 | -2.7207445 | -0.2364395 | 0.95 | median | qi |
差分指標を持つ変数の組み合わせを使って、モデルから予測値を生成することができる。この場合、条件平均と残差標準偏差を組み合わせて、モデルから予測分布を生成し、ggdist::stat_interval()
を使って分布を表示し、データと比較することができる。
%>%
m spread_draws(condition_mean[condition], response_sd) %>%
mutate(y_rep = rnorm(n(), condition_mean, response_sd)) %>%
median_qi(y_rep, .width = c(.95, .8, .5)) %>%
ggplot(aes(y = fct_rev(condition), x = y_rep)) +
geom_interval(aes(xmin = .lower, xmax = .upper)) + #auto-sets aes(color = fct_rev(ordered(.width)))
geom_point(aes(x = response), data = ABC) +
scale_color_brewer()
このモデルがうまくキャリブレーションされていれば、約95%のデータが外側の区間に、80%が次に小さい区間に、50%が最も小さい区間に収まるはずである。
合わせて、データ、事後予測、平均の事後分布。
= m %>%
draws spread_draws(condition_mean[condition], response_sd)
= draws %>%
reps mutate(y_rep = rnorm(n(), condition_mean, response_sd))
%>%
ABC ggplot(aes(y = condition)) +
stat_interval(aes(x = y_rep), .width = c(.95, .8, .5), data = reps) +
stat_pointinterval(aes(x = condition_mean), .width = c(.95, .66), position = position_nudge(y = -0.3), data = draws) +
geom_point(aes(x = response)) +
scale_color_brewer()
compare_levels()
は、ある変数の値をある因子のレベル間で比較することができる。デフォルトでは一対の差分をすべて計算するが、
引数を使用して変更することができる。 comparison =
%>%
m spread_draws(condition_mean[condition]) %>%
compare_levels(condition_mean, by = condition) %>%
ggplot(aes(y = condition, x = condition_mean)) +
stat_halfeye()
gather_draws
と
gather_variables
であるまた、すべてのモデル変数名が列名としてではなく、1つの列 (long-format)
であることを好むかもしれない。tidybayes
を使ってロングフォーマットのデータフレームを得る方法が2つある。これらの方法は、データ処理チェーンのどこで、どのようにロングフォーマットに変換したいかによる:
gather_draws()
と
gather_variables()
。また、ワイド (またはセミワイド)
フォーマットのデータフレームを得るには、spread_draws()
(前述) と tidy_draws()
の2つの方法がある。
gather_draws()
は、すべての変数名を 列に、すべての描画を
列に置くことを除いて、 と対になるものである。 .variable
.value
spread_draws()
%>%
m gather_draws(overall_mean, condition_mean[condition]) %>%
median_qi()
.variable | condition | .value | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|---|
condition_mean | A | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi |
condition_mean | B | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi |
condition_mean | C | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi |
condition_mean | D | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi |
condition_mean | E | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi |
overall_mean | NA | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
なお、condition = NA
は overall_mean
の行に対して、gather_draws()
に渡された仕様の中にその名前のインデックスがないためである。
複数の列を含む計算をする必要がない場合はこれでうまくいくが、spread_draws()
が返す半角フォーマットは、上記の condition_offset
の計算のように、複数の列名を含む計算には非常に有効である。spread_draws
が返すフォーマットで中間計算を行い、その後*変数を1つの列に集めたい場合は、gather_variables()
を使用すると、特別な列でないグループ化されていないすべての変数 (
.chain
, .iteration
, .draw
のような) を集めることができる。
%>%
m spread_draws(overall_mean, condition_mean[condition]) %>%
mutate(condition_offset = condition_mean - overall_mean) %>%
gather_variables() %>%
median_qi()
condition | .variable | .value | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|---|
A | condition_mean | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi |
A | condition_offset | -0.4129033 | -1.6453950 | 0.9101742 | 0.95 | median | qi |
A | overall_mean | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
B | condition_mean | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi |
B | condition_offset | 0.3879801 | -0.7981041 | 1.6785521 | 0.95 | median | qi |
B | overall_mean | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
C | condition_mean | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi |
C | condition_offset | 1.2143535 | 0.0143735 | 2.5476898 | 0.95 | median | qi |
C | overall_mean | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
D | condition_mean | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi |
D | condition_offset | 0.4014766 | -0.8057669 | 1.7446861 | 0.95 | median | qi |
D | overall_mean | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
E | condition_mean | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi |
E | condition_offset | -1.5085301 | -2.7207445 | -0.2364395 | 0.95 | median | qi |
E | overall_mean | 0.6177286 | -0.6883475 | 1.8058598 | 0.95 | median | qi |
ここで、overall_mean
が各条件で繰り返されていることに注意。これは、モデル変数を列間で分散させた後に収集を行ったことがある。
最後に、インデックスをそれ自身の列名として分割するのではなく、生のモデル変数名を列名としたい場合、tidy_draws()
を使用することができる。一般的には spread_draws()
や
gather_draws()
の方が tidy_draws()
よりも便利であるが、多くの種類のベイジアンモデルからデータフレームを生成するための一般的な方法として提供されており、gather_draws()
と spread_draws()
によって内部的に使用されている。
%>%
m tidy_draws() %>%
head(10)
.chain | .iteration | .draw | overall_mean | condition_zoffset[1] | condition_zoffset[2] | condition_zoffset[3] | condition_zoffset[4] | condition_zoffset[5] | response_sd | condition_mean_sd | condition_mean[1] | condition_mean[2] | condition_mean[3] | condition_mean[4] | condition_mean[5] | lp__ | accept_stat__ | stepsize__ | treedepth__ | n_leapfrog__ | divergent__ | energy__ |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0.4720119 | -0.7228089 | 0.5387863 | 1.6000509 | 0.7603937 | -2.1282368 | 0.5490346 | 0.5941826 | 0.0425315 | 0.7921493 | 1.422734 | 0.9238246 | -0.7925493 | -3.3916720 | 0.9812419 | 0.0544657 | 6 | 127 | 0 | 9.6097018 |
1 | 2 | 2 | 0.7776089 | -0.4906112 | 0.0532138 | 1.2960640 | 0.3667496 | -2.1722238 | 0.5470606 | 0.7077093 | 0.4303988 | 0.8152688 | 1.694846 | 1.0371610 | -0.7596942 | -0.1715153 | 0.9997818 | 0.0544657 | 5 | 63 | 0 | 6.2706423 |
1 | 3 | 3 | -0.1013847 | 0.0753446 | 0.6906783 | 1.3778737 | 0.8135068 | -0.5670191 | 0.5573434 | 1.5433165 | 0.0148958 | 0.9645506 | 2.025110 | 1.1541138 | -0.9764747 | 3.0305862 | 0.9971638 | 0.0544657 | 6 | 95 | 0 | 3.3818547 |
1 | 4 | 4 | -0.0086601 | 0.2916825 | 0.6530099 | 1.0097827 | 0.5041831 | -0.4694991 | 0.6155352 | 1.8612685 | 0.5342393 | 1.2067666 | 1.870817 | 0.9297600 | -0.8825239 | 1.4644291 | 0.9806065 | 0.0544657 | 6 | 95 | 0 | 1.0158377 |
1 | 5 | 5 | 0.3126983 | -0.0121558 | 0.4270635 | 1.3580532 | 0.5114565 | -1.0401146 | 0.6161216 | 1.1787490 | 0.2983696 | 0.8160989 | 1.913502 | 0.9155771 | -0.9133358 | 2.3408543 | 0.9869015 | 0.0544657 | 6 | 127 | 0 | 1.9863168 |
1 | 6 | 6 | 0.3534224 | -0.1667149 | 0.3922855 | 0.7505944 | 0.3816615 | -0.5939700 | 0.5174635 | 1.8184037 | 0.0502674 | 1.0667559 | 1.718306 | 1.0474370 | -0.7266549 | 3.6913915 | 0.9842025 | 0.0544657 | 4 | 31 | 0 | 5.4256122 |
1 | 7 | 7 | -0.1594659 | 0.1910058 | 0.8607167 | 1.4978749 | 0.8421032 | -0.7143273 | 0.4984251 | 1.3689105 | 0.1020039 | 1.0187783 | 1.890991 | 0.9932980 | -1.1373160 | 2.8755970 | 0.9918319 | 0.0544657 | 6 | 127 | 0 | -0.1272299 |
1 | 8 | 8 | 1.4268865 | -1.1670336 | -0.4316543 | 0.1962286 | -0.5619779 | -2.0107542 | 0.5383222 | 1.0768350 | 0.1701838 | 0.9620660 | 1.638192 | 0.8217290 | -0.7383640 | 0.6703955 | 0.9668672 | 0.0544657 | 7 | 127 | 0 | 2.6377963 |
1 | 9 | 9 | 1.9375415 | -1.5311064 | -0.7487792 | -0.1065111 | -0.7260632 | -2.3884682 | 0.5635136 | 1.2424804 | 0.0351719 | 1.0071980 | 1.805204 | 1.0354223 | -1.0300833 | 0.6420246 | 0.9714637 | 0.0544657 | 5 | 47 | 0 | 4.8342776 |
1 | 10 | 10 | 1.3272984 | -0.3881331 | -0.1504101 | 0.2346359 | -0.1610924 | -0.8453990 | 0.5369298 | 2.7021155 | 0.2785180 | 0.9208728 | 1.961312 | 0.8920080 | -0.9570674 | 4.3854093 | 0.9961164 | 0.0544657 | 6 | 127 | 0 | 2.2540402 |
tidy_draws()
と gather_variables()
を組み合わせることで、必要であれば ggmcmc::ggs()
と同様の出力を導き出すことも可能である。
%>%
m tidy_draws() %>%
gather_variables() %>%
head(10)
.chain | .iteration | .draw | .variable | .value |
---|---|---|---|---|
1 | 1 | 1 | overall_mean | 0.4720119 |
1 | 2 | 2 | overall_mean | 0.7776089 |
1 | 3 | 3 | overall_mean | -0.1013847 |
1 | 4 | 4 | overall_mean | -0.0086601 |
1 | 5 | 5 | overall_mean | 0.3126983 |
1 | 6 | 6 | overall_mean | 0.3534224 |
1 | 7 | 7 | overall_mean | -0.1594659 |
1 | 8 | 8 | overall_mean | 1.4268865 |
1 | 9 | 9 | overall_mean | 1.9375415 |
1 | 10 | 10 | overall_mean | 1.3272984 |
しかし、繰り返しになるが、この方法では可変インデックスを自動的に処理してくれないので、可変インデックスを気にする必要がない場合以外は、一般的に
spread_draws()
と gather_draws()
を使用することが推奨される。
spread_draws()
と gather_draws()
に渡す仕様の中で正規表現を使い、regex = TRUE
を渡すことで複数の列にマッチさせることができる。この例のフィットでは、変数名
condition_mean [i]
と condition_zoffset [i]
.この2つの変数を1つの正規表現で取り出すことができる。
%>%
m spread_draws(`condition_.*`[condition], regex = TRUE) %>%
head(10)
condition | condition_mean | condition_zoffset | .chain | .iteration | .draw |
---|---|---|---|---|---|
A | 0.0425315 | -0.7228089 | 1 | 1 | 1 |
A | 0.4303988 | -0.4906112 | 1 | 2 | 2 |
A | 0.0148958 | 0.0753446 | 1 | 3 | 3 |
A | 0.5342393 | 0.2916825 | 1 | 4 | 4 |
A | 0.2983696 | -0.0121558 | 1 | 5 | 5 |
A | 0.0502674 | -0.1667149 | 1 | 6 | 6 |
A | 0.1020039 | 0.1910058 | 1 | 7 | 7 |
A | 0.1701838 | -1.1670336 | 1 | 8 | 8 |
A | 0.0351719 | -1.5311064 | 1 | 9 | 9 |
A | 0.2785180 | -0.3881331 | 1 | 10 | 10 |
この結果は、この場合、次のものと同じである。
spread_draws(c(condition_mean, condition_zoffset) [condition] )
と同じであるが、各変数を明示的に列挙する必要はない—これは、例えば、係数に
b_ [some name]
のような命名法を持つモデルで有用である。
不確実性を伴う適合曲線の描画を実証するために、mtcars
データセットの一部に、brms::brm()
を使って、少し素朴なモデルを適合させてみよう。
= brm(
m_mpg ~ hp * cyl,
mpg data = mtcars,
file = "models/tidybayes_m_mpg.rds" # cache model (can be removed)
)
add_epred_draws()
と
ggdist::stat_lineribbon()
を使って、確率帯のあるフィットカーブを描くことができる。
%>%
mtcars group_by(cyl) %>%
data_grid(hp = seq_range(hp, n = 51)) %>%
add_epred_draws(m_mpg) %>%
ggplot(aes(x = hp, y = mpg, color = ordered(cyl))) +
stat_lineribbon(aes(y = .epred)) +
geom_point(data = mtcars) +
scale_fill_brewer(palette = "Greys") +
scale_color_brewer(palette = "Set2")
## Warning: Using the `size` aesthietic with geom_ribbon was deprecated in ggplot2 3.4.0.
## ℹ Please use the `linewidth` aesthetic instead.
## Warning: Unknown or uninitialised column: `linewidth`.
## Warning: Using the `size` aesthietic with geom_line was deprecated in ggplot2 3.4.0.
## ℹ Please use the `linewidth` aesthetic instead.
## Warning: Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
## Unknown or uninitialised column: `linewidth`.
あるいは、適当な数のフィットラインをサンプリングして (たとえば100本) 、それらをオーバープロットすることもできる。
%>%
mtcars group_by(cyl) %>%
data_grid(hp = seq_range(hp, n = 101)) %>%
# NOTE: this shows the use of ndraws to subsample within add_epred_draws()
# ONLY do this IF you are planning to make spaghetti plots, etc.
# NEVER subsample to a small sample to plot intervals, densities, etc.
add_epred_draws(m_mpg, ndraws = 100) %>%
ggplot(aes(x = hp, y = mpg, color = ordered(cyl))) +
geom_line(aes(y = .epred, group = paste(cyl, .draw)), alpha = .1) +
geom_point(data = mtcars) +
scale_color_brewer(palette = "Dark2")
フィットラインの不確かさの例については、vignette("tidy-brms")
または vignette("tidy-rstanarm")
の対応するセクションを参照。
point_interval
と broom::tidy
の互換性モデル比較の例to_broom_names()
と median_qi()
(あるいはより一般的には point_interval()
関数群)
を組み合わせると、broom::tidy()
でサポートされているモデルに対して、簡単に結果を比較することができる。例えば、条件付き平均に対する私たちのモデルの適合を、通常の最小二乗
(OLS) 回帰と比較してみよう。
= lm(response ~ condition, data = ABC) m_linear
emmeans::emmeans
と broom::tidy
を組み合わせると、上記のモデルから条件付き平均の整頓された形式の要約を生成することができる。
= m_linear %>%
linear_results emmeans(~ condition) %>%
tidy(conf.int = TRUE) %>%
mutate(model = "OLS")
linear_results
condition | estimate | std.error | df | conf.low | conf.high | statistic | p.value | model |
---|---|---|---|---|---|---|---|---|
A | 0.1815842 | 0.173236 | 45 | -0.1673310 | 0.5304993 | 1.048190 | 0.3001485 | OLS |
B | 1.0142144 | 0.173236 | 45 | 0.6652993 | 1.3631296 | 5.854526 | 0.0000005 | OLS |
C | 1.8745839 | 0.173236 | 45 | 1.5256687 | 2.2234990 | 10.820985 | 0.0000000 | OLS |
D | 1.0271794 | 0.173236 | 45 | 0.6782642 | 1.3760946 | 5.929366 | 0.0000004 | OLS |
E | -0.9352260 | 0.173236 | 45 | -1.2841411 | -0.5863108 | -5.398567 | 0.0000024 | OLS |
私たちのモデルから対応する適合度を導き出すことができる。
= m %>%
bayes_results spread_draws(condition_mean[condition]) %>%
median_qi(estimate = condition_mean) %>%
to_broom_names() %>%
mutate(model = "Bayes")
bayes_results
condition | estimate | conf.low | conf.high | .width | .point | .interval | model |
---|---|---|---|---|---|---|---|
A | 0.1923963 | -0.1587834 | 0.5495929 | 0.95 | median | qi | Bayes |
B | 1.0007694 | 0.6510203 | 1.3431703 | 0.95 | median | qi | Bayes |
C | 1.8382099 | 1.4805718 | 2.1913833 | 0.95 | median | qi | Bayes |
D | 1.0180656 | 0.6615895 | 1.3503778 | 0.95 | median | qi | Bayes |
E | -0.8904054 | -1.2397288 | -0.5440394 | 0.95 | median | qi | Bayes |
ここで、to_broom_names()
は .lower
と
.upper
を conf.low
と conf.high
に変換し、比較に必要な列の名前 ( condition
,
estimate
, conf.low
, conf.high
)
をすべて簡単に並べられるようにする。これにより、2つの整頓されたデータフレームを
bind_rows
を使って結合し、プロットすることが簡単になる。
bind_rows(linear_results, bayes_results) %>%
mutate(condition = fct_rev(condition)) %>%
ggplot(aes(y = condition, x = estimate, xmin = conf.low, xmax = conf.high, color = model)) +
geom_pointinterval(position = position_dodge(width = .3))
OLSモデルと比較して、ベイズモデルで全体の平均に向かって縮小していることを観察してみよう。
unspread_draws
と ungather_draws
を使用した bayesplot
との互換性他のパッケージの関数は、変数を列、ドローを行とするデータフレームまたはマトリックスの形式でドローを期待するだろう。これは、tidy_draws()
が返す形式であるが、gather_draws()
や
spread_draws()
は、変数のインデックスを列で分割している。
spread_draws()
や gather_draws()
関数を使って描画を何らかの方法で変換し、bayesplot
のような他のパッケージの関数に渡すために、描画 \(\times\) の変数フォーマットに 戻す
ようにするとよいだろう。unspread_draws()
と
ungather_draws()
関数は spread_draws()
と
gather_draws()
を逆にして、インデックスを含む変数列名と行としての描画を持つデータフレームを返す。
例として、先ほどの compare_levels()
の例をもう一度やってむが、ggdist::stat_eye()
の代わりに
bayesplot::mcmc_areas()
を使って結果をプロットしてみよう。まず、compare_levels()
の結果は次のようになる。
%>%
m spread_draws(condition_mean[condition]) %>%
compare_levels(condition_mean, by = condition) %>%
head(10)
.chain | .iteration | .draw | condition | condition_mean |
---|---|---|---|---|
1 | 1 | 1 | B - A | 0.7496179 |
1 | 2 | 2 | B - A | 0.3848700 |
1 | 3 | 3 | B - A | 0.9496548 |
1 | 4 | 4 | B - A | 0.6725274 |
1 | 5 | 5 | B - A | 0.5177293 |
1 | 6 | 6 | B - A | 1.0164884 |
1 | 7 | 7 | B - A | 0.9167743 |
1 | 8 | 8 | B - A | 0.7918821 |
1 | 9 | 9 | B - A | 0.9720261 |
1 | 10 | 10 | B - A | 0.6423548 |
bayesplot::mcmc_areas()
に渡せるバージョンを得るために必要なことは、最初に行った
spread_draws()
の呼び出しを反転させることである。
%>%
m spread_draws(condition_mean[condition]) %>%
compare_levels(condition_mean, by = condition) %>%
unspread_draws(condition_mean[condition]) %>%
head(10)
## Warning: `spread_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `spread()` instead.
## ℹ The deprecated feature was likely used in the tidybayes package.
## Please report the issue at <]8;;https://github.com/mjskay/tidybayes/issues/newhttps://github.com/mjskay/tidybayes/issues/new]8;;>.
.chain | .iteration | .draw | condition_mean[B - A] | condition_mean[C - A] | condition_mean[C - B] | condition_mean[D - A] | condition_mean[D - B] | condition_mean[D - C] | condition_mean[E - A] | condition_mean[E - B] | condition_mean[E - C] | condition_mean[E - D] |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0.7496179 | 1.380203 | 0.6305850 | 0.8812931 | 0.1316753 | -0.4989097 | -0.8350808 | -1.584699 | -2.215284 | -1.716374 |
1 | 2 | 2 | 0.3848700 | 1.264447 | 0.8795767 | 0.6067623 | 0.2218922 | -0.6576845 | -1.1900930 | -1.574963 | -2.454540 | -1.796855 |
1 | 3 | 3 | 0.9496548 | 2.010215 | 1.0605599 | 1.1392180 | 0.1895632 | -0.8709967 | -0.9913705 | -1.941025 | -3.001585 | -2.130588 |
1 | 4 | 4 | 0.6725274 | 1.336577 | 0.6640500 | 0.3955207 | -0.2770067 | -0.9410567 | -1.4167632 | -2.089291 | -2.753341 | -1.812284 |
1 | 5 | 5 | 0.5177293 | 1.615133 | 1.0974032 | 0.6172075 | 0.0994782 | -0.9979250 | -1.2117054 | -1.729435 | -2.826838 | -1.828913 |
1 | 6 | 6 | 1.0164884 | 1.668039 | 0.6515501 | 0.9971696 | -0.0193188 | -0.6708690 | -0.7769223 | -1.793411 | -2.444961 | -1.774092 |
1 | 7 | 7 | 0.9167743 | 1.788987 | 0.8722125 | 0.8912941 | -0.0254803 | -0.8976927 | -1.2393200 | -2.156094 | -3.028307 | -2.130614 |
1 | 8 | 8 | 0.7918821 | 1.468009 | 0.6761263 | 0.6515452 | -0.1403370 | -0.8164633 | -0.9085478 | -1.700430 | -2.376556 | -1.560093 |
1 | 9 | 9 | 0.9720261 | 1.770032 | 0.7980056 | 1.0002504 | 0.0282243 | -0.7697813 | -1.0652552 | -2.037281 | -2.835287 | -2.065506 |
1 | 10 | 10 | 0.6423548 | 1.682794 | 1.0404388 | 0.6134900 | -0.0288648 | -1.0693036 | -1.2355854 | -1.877940 | -2.918379 | -1.849075 |
それを直接 bayesplot::mcmc_areas()
に渡すことができる。unspread_draws()
の引数
drop_indices = TRUE
は、.chain
,
.iteration
, および .draw
が出力に含まれるべきではないことを示す。
%>%
m spread_draws(condition_mean[condition]) %>%
compare_levels(condition_mean, by = condition) %>%
unspread_draws(condition_mean[condition], drop_indices = TRUE) %>%
::mcmc_areas() bayesplot
gather_draws()
や gather_variables()
で生成された整頓された描画を扱う場合、ungather_draws()
関数はそれらの描画を draw \(\times\)
という変数形式に変換する。これは unspread_draws()
と同じ構文を持っている。
emmeans
(旧 lsmeans
) との互換性emmeans::emmeans()
関数は、多数の種類の対比を含むモデルからマージナル推定値を生成するための便利な構文を提供する。また、MCMCglmm
, rstanarm
, brms
のようないくつかのベイズモデリングパッケージをサポートしている。
しかし、整頓されたフォーマットでの描画は提供されていない。gather_emmeans_draws()
関数は emmeans
の出力を整頓された形式に変換し、emmeans
の参照グリッドを維持し、ロングフォーマットのドローを持つ
.value
の列を追加する。
(別のアプローチとして、emmeans
コントラスト法を使用し、emmeans_comparison()
で emmeans
コントラストを変換する。
メソッドを、tidybayes::compare_levels()
で使用できる比較関数に変換する。のドキュメントを参照。
emmeans_comparison()
を参照) 。
rstanarm
または brms
を使用するrstanarm
と brms
は、emmeans::emmeans()
と一緒に使っても同じような動作になる。以下の例では、rstanarm
を使用しているが、brms
でも同様に動作するはずである。
この rstanarm
のモデルから考えると。
= stan_glm(response ~ condition, data = ABC) m_rst
emmeans::emmeans()
を使って、不確実性を伴う条件付き平均を求めることができる。
%>%
m_rst emmeans( ~ condition) %>%
gather_emmeans_draws() %>%
median_qi()
condition | .value | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A | 0.1839216 | -0.1737448 | 0.5399800 | 0.95 | median | qi |
B | 1.0138490 | 0.6394168 | 1.3551706 | 0.95 | median | qi |
C | 1.8682159 | 1.5290403 | 2.2075733 | 0.95 | median | qi |
D | 1.0265241 | 0.6727074 | 1.3780107 | 0.95 | median | qi |
E | -0.9316006 | -1.2598607 | -0.5845776 | 0.95 | median | qi |
または、emmeans::emmeans()
emmeans::contrast()
、すべてのペアワイズ比較を行うことができる。
%>%
m_rst emmeans( ~ condition) %>%
contrast(method = "pairwise") %>%
gather_emmeans_draws() %>%
median_qi()
contrast | .value | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|
A - B | -0.8241267 | -1.3265320 | -0.3296754 | 0.95 | median | qi |
A - C | -1.6818203 | -2.1729825 | -1.1927322 | 0.95 | median | qi |
A - D | -0.8484698 | -1.3617588 | -0.3429223 | 0.95 | median | qi |
A - E | 1.1102204 | 0.6142124 | 1.6199968 | 0.95 | median | qi |
B - C | -0.8592072 | -1.3348505 | -0.3867405 | 0.95 | median | qi |
B - D | -0.0188042 | -0.5064541 | 0.4846524 | 0.95 | median | qi |
B - E | 1.9457872 | 1.4444502 | 2.4137282 | 0.95 | median | qi |
C - D | 0.8398055 | 0.3274180 | 1.3475858 | 0.95 | median | qi |
C - E | 2.8057222 | 2.3211588 | 3.2873458 | 0.95 | median | qi |
D - E | 1.9617316 | 1.4741161 | 2.4367297 | 0.95 | median | qi |
emmeans::emmeans()
がサポートする多数のコントラストタイプの一覧は、emmeans::pairwise.emmc()
のドキュメントを参照。
前回と同様に、表を使う代わりに結果をプロットすることができる。
%>%
m_rst emmeans( ~ condition) %>%
contrast(method = "pairwise") %>%
gather_emmeans_draws() %>%
ggplot(aes(x = .value, y = contrast)) +
stat_halfeye()
gather_emmeans_draws()
は、異なる参照グリッドからの推定値を含む オブジェクトもサポートしている
(参照グリッドの詳細については
を参照)。出力の各行の参照グリッドを示すために、
というデフォルト名を持つ列が追加される。 emm_list
emmeans::ref_grid()
.grid
%>%
m_rst emmeans(pairwise ~ condition) %>%
gather_emmeans_draws() %>%
median_qi()
condition | contrast | .grid | .value | .lower | .upper | .width | .point | .interval |
---|---|---|---|---|---|---|---|---|
A | NA | emmeans | 0.1839216 | -0.1737448 | 0.5399800 | 0.95 | median | qi |
B | NA | emmeans | 1.0138490 | 0.6394168 | 1.3551706 | 0.95 | median | qi |
C | NA | emmeans | 1.8682159 | 1.5290403 | 2.2075733 | 0.95 | median | qi |
D | NA | emmeans | 1.0265241 | 0.6727074 | 1.3780107 | 0.95 | median | qi |
E | NA | emmeans | -0.9316006 | -1.2598607 | -0.5845776 | 0.95 | median | qi |
NA | A - B | contrasts | -0.8241267 | -1.3265320 | -0.3296754 | 0.95 | median | qi |
NA | A - C | contrasts | -1.6818203 | -2.1729825 | -1.1927322 | 0.95 | median | qi |
NA | A - D | contrasts | -0.8484698 | -1.3617588 | -0.3429223 | 0.95 | median | qi |
NA | A - E | contrasts | 1.1102204 | 0.6142124 | 1.6199968 | 0.95 | median | qi |
NA | B - C | contrasts | -0.8592072 | -1.3348505 | -0.3867405 | 0.95 | median | qi |
NA | B - D | contrasts | -0.0188042 | -0.5064541 | 0.4846524 | 0.95 | median | qi |
NA | B - E | contrasts | 1.9457872 | 1.4444502 | 2.4137282 | 0.95 | median | qi |
NA | C - D | contrasts | 0.8398055 | 0.3274180 | 1.3475858 | 0.95 | median | qi |
NA | C - E | contrasts | 2.8057222 | 2.3211588 | 3.2873458 | 0.95 | median | qi |
NA | D - E | contrasts | 1.9617316 | 1.4741161 | 2.4367297 | 0.95 | median | qi |
MCMCglmm
の使用上と同じ例をもう一度やってみよう。今度は rstanarm
の代わりに MCMCglmm::MCMCglmm()
を使う。MCMCglmm()
を使うときに唯一違うのは、MCMCglmm()
を
emmeans()
とともに使うには、モデルの適合に使われた元のデータも
emmeans()
の呼び出しに渡さなければならないことである(詳細は
vignette("models ", package =" emmeans"))
を参照)。
まず、モデルのフィッティングを行う。
# MCMCglmm does not support tibbles directly,
# so we convert ABC to a data.frame on the way in
= MCMCglmm(response ~ condition, data = as.data.frame(ABC)) m_glmm
これで、emmeans()
と gather_emmeans_draws()
は rstanarm
と全く同じように使えるが、emmeans()
の呼び出しの中に
data
の引数を含める必要がある。
%>%
m_glmm emmeans( ~ condition, data = ABC) %>%
contrast(method = "pairwise") %>%
gather_emmeans_draws() %>%
ggplot(aes(x = .value, y = contrast)) +
stat_halfeye()