从中提取并可视化整齐的绘图brms模型

马修·凯

2024-09-15

介绍

这个小插曲描述了如何使用河豚ggdist(ggdist)要提取和可视化的包整齐的的数据帧从模型变量、平均值和预测来自brms::brm。有关更一般的介绍河豚及其在通用贝叶斯上的使用建模语言(如Stan和JAGS),请参见渐晕(“tidybayes”).

安装程序

运行此vignette需要以下库:

图书馆(马格里特)
图书馆(dplyr)
图书馆(咕噜声)
图书馆(适用于猫)
图书馆(第三年)
图书馆(建模师)
图书馆(ggdist)
图书馆(河豚)
图书馆(ggplot2)
图书馆(牛头图)
图书馆(第一个)
图书馆(brms)
图书馆(gg排斥)
图书馆(R彩色啤酒)
图书馆(gganimate)
图书馆(后部)
图书馆(分配)

主题集(theme_tidybayes乐队()+ 面板_订单())

这些选项有助于斯坦跑得更快:

rstan_options(选项)(自动写入(_W)= 真的)
选项(mc.孔=平行::探测器核心())

示例数据集

为了证明河豚,我们将使用一个简单的数据集分别从5种条件下进行10次观察:

设置种子(5)
n个= 10
n条件= 5
基础知识=
  易怒的(
    条件= 代表(c(c)(“A”,“B”,“C”,“D”,“E”),n),
    响应= rnorm公司(n)* 5,c(c)(0,1,2,1,-1),0.5)
)

数据快照如下所示:

(美国广播公司,10)
条件 响应
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

这是一个典型的整洁格式的数据帧:每行一个观察值。图形化:

基础知识%>%
  ggplot图(原子发射光谱(年=条件,x个=响应))+
  地理点()

模型

让我们拟合一个收缩到全局的层次模型平均值:

= 商业风险管理(
响应~(1|条件),
  数据=ABC,
  先前= c(c)(
    先前的(正常的(0,1),类=截距),
    先前的(学生_t(,0,1),类=sd),
    先前的(学生_t(,0,1),类=西格玛)
),
  控制= 列表(自适应_斜率=.99),
  
  文件= “型号/tidy-brms_m.rds” #缓存模型(可以删除)
)

结果如下:

##系列:高斯##链接:mu=身份;sigma=标识##公式:响应~(1|条件)##数据:ABC(观察次数:50)##绘制:4条链,每条链的iter=2000;预热=1000;thin=1;##预热后总抽吸=4000## ##多级超参数:##~条件(级别数:5)##估算估算值。错误l-95%CI u-95%CI Rhat Bulk_ESS Tail_ESS##sd(截距)1.17 0.43 0.60 2.22 1.00 944 1542## ##回归系数:##估算估算值。错误l-95%CI u-95%CI Rhat Bulk_ESS Tail_ESS##截距0.50 0.48-0.49 1.41 1.00 904 1204## ##进一步的分布参数:##估算估算值。错误l-95%CI u-95%CI Rhat Bulk_ESS Tail_ESS##西格玛0.56 0.06 0.46 0.70 1.00 2057 2243## ##使用抽样(NUTS)对图纸进行抽样。对于每个参数,Bulk_ESS##和Tail_ESS是有效的样本量度量,Rhat是潜在的##分裂链上的比例折减系数(收敛时,Rhat=1)。

使用从潮汐格式中的拟合提取绘制展开_绘制

现在我们有了结果,乐趣开始了:抽奖以整洁的格式!首先,我们将使用获取变量()函数获取原始模型变量名列表,以便我们知道我们可以从模型中提取的变量:

获取变量(米)
##[1]“b_Intercept”“sd_condition__Intercept”“sigma”“r_condition[A,Intercept]”##[5]“r_condition[B,Intercept]”“r_condition[C,Intercept”“r_condition[D,Intercett]”“r _condition[E,Intercert]”##[9]“lp__”“accept_stat__”“stepsize_”“treedepth__”##[13]“n_supfrog__”“发散__”“能量__”

在这里,b_截距是全球平均值r_条件[]变量是每个变量的平均值的偏移量条件。给定这些变量:

我们可能需要一个数据帧,其中每一行都是来自其中之一r_条件[A,截距],r_条件[B,截距],…[C,…],…[D,…],或…[英…],以及我们在哪里列索引从哪个链/迭代/绘制行以及哪个条件(A类E类)它是为了。这将允许我们可以轻松计算按条件分组的数量,或生成绘图根据条件使用ggplot,甚至将绘图与原始数据合并到同时绘制数据和后验概率。

的主力河豚spread_draws()函数,它为我们进行此提取。它包括一个简单的规范格式,我们可以使用它来提取变量及其索引转换为tid-format数据帧。

以整洁的格式将变量索引收集到单独的列中数据帧

给定模型中的一个变量,如下所示:

r_条件[D,截距]

我们可以提供spread_draws()带有一列规范如下:

条件[条件,条件]

在哪里?条件对应于D类学期对应于拦截。有什么都不太神奇spread_draws()与一起执行此规范:在引擎盖下,它将变量索引拆分为逗号和空格(可以通过更改九月参数)。它允许您将列分配给结果按顺序索引。所以r_条件[D,截距]具有索引D类拦截、和spread_draws()让我们将这些索引提取为中的列由此产生的整齐的绘图数据帧r_条件:

%>%
  展开_绘制(r_条件[条件,条件])%>%
  (10)
条件 学期 r_条件 .链条 .迭代 .绘制
A类 拦截 0.6829060 1 1 1
A类 拦截 -0.7785857 1 2 2
A类 拦截 -0.5797397 1
A类 拦截 -0.7168785 1 4 4
A类 拦截 -0.7858417 1 5 5
A类 拦截 -0.8177604 1 6 6
A类 拦截 -0.4562683 1 7 7
A类 拦截 -0.2476565 1 8 8
A类 拦截 0.0870252 1 9 9
A类 拦截 -0.0982682 1 10 10

我们可以为索引列选择任何名称;例如。:

%>%
  展开_绘制(r条件[c,t])%>%
  (10)
c(c) t吨 r_条件 .链条 .迭代 .绘制
A类 拦截 0.6829060 1 1 1
A类 拦截 -0.7785857 1 2 2
A类 拦截 -0.5797397 1
A类 拦截 -0.7168785 1 4 4
A类 拦截 -0.7858417 1 5 5
A类 拦截 -0.8177604 1 6 6
A类 拦截 -0.4562683 1 7 7
A类 拦截 -0.2476565 1 8 8
A类 拦截 0.0870252 1 9 9
A类 拦截 -0.0982682 1 10 10

但之前的名字更具描述性,也不那么神秘举个例子可能更好。

在这个特定的模型中,只有一个术语(拦截),因此我们可以将该索引全部省略为每个都要条件以及r_条件对于该条件:

%>%
  展开_绘制(r_条件[条件,])%>%
  (10)
条件 _条件 .链条 .迭代 .绘制
A类 0.6829060 1 1 1
A类 -0.7785857 1 2 2
A类 -0.5797397 1
A类 -0.7168785 1 4 4
A类 -0.7858417 1 5 5
A类 -0.8177604 1 6 6
A类 -0.4562683 1 7 7
A类 -0.2476565 1 8 8
A类 0.0870252 1 9 9
A类 -0.0982682 1 10 10

注:如果您使用过spread_draws()对于Stan或JAGS的原始样本,您可能习惯于使用恢复类型之前spread_draws()得到索引列值返回(例如,如果索引是一个因子)。这不是使用时需要spread_draws()圣塔那主义模型,因为这些模型已经包含了变量名中的信息。有关更多信息恢复类型,请参阅渐晕(“tidybayes”).

点总结和间隔

使用简单的模型变量

河豚提供了一系列用于生成以整洁的格式对绘图进行点总结和间隔。这些函数遵循命名方案[median|means|mode]_[qi|hdi]例如,中位数_qi(),mean_qi(),mode_hdi(),依此类推。名字(在_)表示积分汇总的类型,第二个名称指示间隔的类型。产生分位数间隔(也称为等尾间隔、中心间隔或百分位数间隔)和高密度指数产生最高(后部)密度间隔。也可以应用自定义点汇总或间隔函数使用点间隔()功能。

例如,我们可以提取对应于后部的绘图总平均值和标准差的分布观察:

%>%
  展开_绘制(b_截距,σ)%>%
  (10)
.链条 .迭代 .绘制 b_截距 西格玛
1 1 1 -0.2767032 0.5674665
1 2 2 0.8924211 0.5621870
1 0.9407381 0.5541763
1 4 4 0.9993291 0.5526330
1 5 5 1.0384020 0.5439572
1 6 6 1.4137790 0.5798467
1 7 7 0.3329987 0.5507381
1 8 8 0.5616170 0.5364457
1 9 9 0.1770721 0.5441246
1 10 10 0.3237930 0.4982546

喜欢与r_条件[条件,条件],这给了我们一个整洁的数据帧。如果我们想要变量,我们可以应用中位数_qi():

%>%
  展开_绘制(b_截距,σ)%>%
  中天_qi(b_Intercept,西格玛)
b_截距 b_截获功率 b_截距上部 西格玛 信号低 sigma.上部 .宽度 .间隔
0.5258874 -0.4902497 1.40569 0.5571528 0.4558006 0.6957939 0.95 中值的

我们可以指定要从中获取中值和间隔的列,或者如果我们省略列列表,中位数_qi()将使用不是分组列或特殊列的每个列(比如.链条,.迭代,或.绘制). 因此,在上述示例中,b_截距西格玛是多余的参数中位数_qi()因为他们也是我们唯一的专栏从模型中收集。因此,我们可以将其简化为:

%>%
  展开_绘制(b_截距,σ)%>%
  中天_qi()
b_截距 b_拦截器功率 b_截距上部 西格玛 信号低 sigma.上部 .宽度 .间隔
0.5258874 -0.4902497 1.40569 0.5571528 0.4558006 0.6957939 0.95 中值的

如果您希望有一个长格式的间隔列表,请使用gather_draws()而是:

%>%
  gather_图纸(b_截距,σ)%>%
  中天_qi()
.变量 .值 .下部 .上部 .宽度 .间隔
_拦截 0.5258874 -0.4902497 1.4056903 0.95 中值的
西格玛 0.5571528 0.4558006 0.6957939 0.95 中值的

有关更多信息gather_draws(),请参阅渐晕(“tidybayes”).

使用索引模型变量

当我们有一个具有一个或多个索引的模型变量时,例如r_条件,我们可以申请中位数_qi()(或中的其他功能点间隔()家人)之前:

%>%
  展开_绘制(r_条件[条件,])%>%
  中天_qi()
条件 r_条件 .下部 .上部 .宽度 .间隔
A类 -0.3363530 -1.2325960 0.7343642 0.95 中值的
B类 0.4798242 -0.4408264 1.5448895 0.95 中值的
C类 1.3179042 0.4059274 2.3755540 0.95 中值的
D类 0.4981223 -0.4433201 1.5536575 0.95 中值的
E类 -1.3978927 -2.3576833 -0.3957483 0.95 中值的

是怎么做到的中位数_qi()知道要聚合什么吗?数据帧由返回spread_draws()按全部自动分组传递给它的索引变量;在这种情况下,这意味着spread_draws()将结果分组条件.中位数_qi()尊重这些群体,并计算所有组内的点汇总和间隔。然后,因为没有向传递任何列中位数_qi(),它只针对非专业(.-前缀)和非组列,r_条件。因此,上面的缩写语法是相当于这个更详细的调用:

%>%
  展开_绘制(r_条件[条件,])%>%
  分组方式(_B)(条件)%>%   #此行不需要(由spreaddraws完成)
  中天_qi(r_条件)#b不是必需的(它是唯一的非组列)
条件 r_条件 .下部 .上部 .宽度 .间隔
A类 -0.3363530 -1.2325960 0.7343642 0.95 中值的
B类 0.4798242 -0.4408264 1.5448895 0.95 中值的
C类 1.3179042 0.4059274 2.3755540 0.95 中值的
D类 0.4981223 -0.4433201 1.5536575 0.95 中值的
E类 -1.3978927 -2.3576833 -0.3957483 0.95 中值的

河豚还提供了后部::summare_draws()用于分组数据帧(tidybayes::summaries_draws.grouped_df()),你可以用于快速获得收敛诊断:

%>%
  展开_绘制(r_条件[条件,])%>%
  summary_draws(总结_绘制)()
条件 变量 意思是 中值的 标准偏差 疯狂的 问题5 第95季度 拉赫特 ess_块 ess_邮件
A类 _条件 -0.3121398 -0.3363530 0.4978955 0.4799092 -1.0782228 0.5256269 1.002543 971.7765 1267.447
B类 r_条件 0.4928093 0.4798242 0.4999156 0.4744824 -0.3005635 1.3402506 1.003311 983.1190 1325.680
C类 r_条件 1.3327741 1.3179042 0.5009147 0.4778770 0.5567025 2.1884327 1.003105 993.5292 1489.303
D类 r_条件 0.5118006 0.4981223 0.5020947 0.4765011 -0.2773801 1.3607620 1.001995 1012.8868 1395.754
E类 _条件 -1.3883041 -1.3978927 0.4995347 0.4680347 -2.1723234 -0.5349330 1.002854 989.8028 1391.940

以单一整洁的格式组合具有不同索引的变量数据帧

spread_draws()gather_draws()支持将具有不同索引的变量提取到同一数据中框架。具有相同名称的索引将自动匹配,并且根据需要复制值,以便为所有值生成一行所有指标水平的组合。例如,我们可能想计算每个条件的平均值(称为条件_平均值). 在这个模型中,这意味着截距(b_截距)加上给定条件下的影响(r_条件).

我们可以从b_截距r_条件在单个数据帧中:

%>% 
  展开_绘制(b_截距,r_条件[条件,])%>%
  (10)
.链条 .迭代 .绘制 b_截距 条件 r_条件
1 1 1 -0.2767032 A类 0.6829060
1 1 1 -0.2767032 B类 1.1563864
1 1 1 -0.2767032 C类 2.1754891
1 1 1 -0.2767032 D类 1.0605452
1 1 1 -0.2767032 E类 -0.3957730
1 2 2 0.8924211 A类 -0.7785857
1 2 2 0.8924211 B类 -0.0145459
1 2 2 0.8924211 C类 0.8032023
1 2 2 0.8924211 D类 0.2212085
1 2 2 0.8924211 E类 -1.5760299

在每次绘图中,b_截距根据需要重复对应的每个索引_条件因此突变可以使用dplyr的函数来求它们的和,条件_平均值(这是每个条件的平均值):

%>%
  展开_绘制(`b_截距`,r_条件[条件,])%>%
  突变(条件_平均值=b_截距+r_条件)%>%
  中天_qi(条件平均值)
条件 条件_平均值 .下部 .上部 .宽度 .间隔
A类 0.1898111 -0.1464277 0.5360261 0.95 中值的
B类 0.9984930 0.6399830 1.3346013 0.95 中值的
C类 1.8379430 1.4924008 2.1761012 0.95 中值的
D类 1.0165100 0.6697091 1.3640797 0.95 中值的
E类 -0.8840828 -1.2365972 -0.5282710 0.95 中值的

中位数_qi()使用整洁的评估(参见vignette(“tidy-evaluation”,package=“rlang”)),所以它可以采用列表达式,而不仅仅是列名。因此,我们可以简化上述示例通过移动计算条件_平均值突变进入之内中位数_qi():

%>%
  展开_绘制(b_Intercept,r_condition[条件,])%>%
  中天_qi(条件_平均值=b_截距+r_条件)
条件 条件_平均值 .下部 .上部 .宽度 .间隔
A类 0.1898111 -0.1464277 0.5360261 0.95 中值的
B类 0.9984930 0.6399830 1.3346013 0.95 中值的
C类 1.8379430 1.4924008 2.1761012 0.95 中值的
D类 1.0165100 0.6697091 1.3640797 0.95 中值的
E类 -0.8840828 -1.2365972 -0.5282710 0.95 中值的

绘制具有多个概率级别的间隔

中位数_qi()其姊妹函数可以生成通过设置.宽度=参数:

%>%
  展开_绘制(b_Intercept,r_condition[条件,])%>%
  中天_qi(条件_平均值=b_截距+r_条件,.宽度= c(c)(.95, .8, .5))
条件 条件_平均值 .下部 .上部 .宽度 .间隔
A类 0.1898111 -0.1464277 0.5360261 0.95 中值的
B类 0.9984930 0.6399830 1.3346013 0.95 中值的
C类 1.8379430 1.4924008 2.1761012 0.95 中值的
D类 1.0165100 0.6697091 1.3640797 0.95 中值的
E类 -0.8840828 -1.2365972 -0.5282710 0.95 中值的
A类 0.1898111 -0.0339645 0.4211348 0.80 中值的
B类 0.9984930 0.7657473 1.2241548 0.80 中值的
C类 1.8379430 1.6071955 2.0572413 0.80 中值的
D类 1.0165100 0.7855210 1.2417771 0.80 中值的
E类 -0.8840828 -1.1073737 -0.6556436 0.80 中值的
A类 0.1898111 0.0777964 0.3065811 0.50 中值的
B类 0.9984930 0.8811815 1.1139238 0.50 中值的
C类 1.8379430 1.7170860 1.9531632 0.50 中值的
D类 1.0165100 0.8977555 1.1336757 0.50 中值的
E类 -0.8840828 -1.0081410 -0.7674066 0.50 中值的

结果格式简洁:每组一行,不确定性间隔宽度(.宽度). 这有助于绘图。对于示例,分配-.宽度线宽美学将显示所有间隔,使粗线条与间隔较小。这个ggdist::地理点间隔()地理自动设置线宽适当的美学基于.宽度数据中的列,以生成具有多个概率级别的点:

%>%
  展开_绘制(b_截距,r_条件[条件,])%>%
  中天_qi(条件_平均值=b_截距+r_条件,.宽度= c(c)(.95, .66))%>%
  ggplot图(原子发射光谱(年=条件,x个=条件平均值,克敏=.降低,x最大值=.上部))+
  地理点间隔()

具有密度的间隔

要查看密度和间隔,我们可以使用ggdist::stat_eye()(“眼图”,结合间隔小提琴情节),或ggdist::stat_halfeye()(间隔+密度图):

%>%
  展开_绘制(b_截距,r_条件[条件,])%>%
  突变(条件_平均值=b_截距+r_条件)%>%
  ggplot图(原子发射光谱(年=条件,x个=条件(平均值))+
  统计_半眼()

或者说你想用颜色标注密度的一部分;这个填满在所有地理环境中,板坯的美学可以不同中的统计数据ggdist::geom_slabinterval()家庭,包括ggdist::stat_halfeye()例如,如果您想注释特定领域的实际等效区域(ROPE),您可以这样做:

%>%
  展开_绘制(b_截距,r_条件[条件,])%>%
  突变(条件_平均值=b_截距+r_条件)%>%
  ggplot图(原子发射光谱(年=条件,x个=条件平均值,填充= 后统计(防抱死制动系统(x)<.8)))+
  统计_半眼()+
  地理vline(辛特西普= c(c)(-.8, .8),线型= “虚线”)+
  缩放填充手动(值= c(c)(“灰色80”,“天蓝色”))

分布的其他可视化:统计_不稳定间隔

有多种其他统计信息可用于可视化分布在中ggdist::geom_slabinterval()统计数据和几何图形:

地理和统计的斯拉宾特瓦尔家族

请参见渐晕(“slabinterval”,package=“ggdist”)对于概述。

后验均值和预测

而不是像前面那样手动计算条件平均值例如,我们可以使用添加_预先绘制(),这是类似的brms::后验_epred()(从后验预测的期望;即后验分布条件表示),但使用整洁的数据格式。我们可以将其与建模器::data_grid()首先生成描述预测,然后将该网格转换为长格式数据从条件手段中提取的框架:

基础知识%>%
  数据网格(条件)%>%
  添加_预先绘制(米)%>%
  (10)
条件 .行 .链条 .迭代 .绘制 .epred(.epred)
A类 1 不适用 不适用 1 0.4062028
A类 1 不适用 不适用 2 0.1138354
A类 1 不适用 不适用 0.3609984
A类 1 不适用 不适用 4 0.2824506
A类 1 不适用 不适用 5 0.2525603
A类 1 不适用 不适用 6 0.5960186
A类 1 不适用 不适用 7 -0.1232696
A类 1 不适用 不适用 8 0.3139605
A类 1 不适用 不适用 9 0.2640973
A类 1 不适用 不适用 10 0.2255247

为了绘制这个示例,我们还将展示ggdist::stat_pointerval()而不是ggdist::地理点间隔(),它总结了对ggplot内的点和间隔:

基础知识%>%
  数据网格(条件)%>%
  添加_预先绘制(米)%>%
  ggplot图(原子发射光谱(x个=.epred、,年=条件))+
  统计点间隔(.宽度= c(c)(.66, .95))

分位数点图

如果alpha级别正好与无论你想做什么决定,都要做一个后部更好(因此上面的眼图)。另一方面从密度图推断不准确(估计一个密度图的面积形状与另一个形状的比例是一项艰巨的感知任务)。推理关于频率格式的概率更容易,激励分位数点图(凯伊(Kay et)2016年,费尔南德斯等人2018年),它还允许精确估计任意间隔(向下至绘图的点分辨率,示例中为100(见下文)。

在tidybays的slabinterval geoms家族中dotsinteval公司家庭,其中自动确定点图的适当箱子大小,并可以根据样本计算分位数以构建分位数点图。ggdist::stat_dotsingeval()变体是为使用而设计的吗样品上:

基础知识%>%
  数据网格(条件)%>%
  添加_预先绘制(米)%>%
  ggplot图(原子发射光谱(x个=.epred、,年=条件))+
  统计时间间隔(分位数= 100)

这个想法是为了避免把后面的表示一个标准点或区间,但表示它比如说100个近似相等的点。

后验预测

在哪里?添加_预先绘制()类似于brms::后验_epred(),添加预测图纸()类似于brms::posterrior_predict(),抽签从后验预测分布来看。

下面是绘制的后验预测分布示例使用ggdist::stat_slab():

基础知识%>%
  数据网格(条件)%>%
  添加预测图纸(米)%>%
  ggplot图(原子发射光谱(x个=.预测,年=条件))+
  统计实验室()

我们还可以使用ggdist::stat_interval()绘制数据旁边的预测带:

基础知识%>%
  数据网格(条件)%>%
  添加预测图纸(米)%>%
  ggplot图(原子发射光谱(年=条件,x个=预测))+
  统计间隔(_I)(.宽度= c(c)(.50, .80, .95, .99))+
  地理点(原子发射光谱(x个=响应),数据=美国广播公司)+
  缩放彩色打印机()

总之,数据、后验预测和后验分布指的是:

网格=基础知识%>%
  数据网格(条件)

方法=网格%>%
  添加_预先绘制(米)

预放电=网格%>%
  添加预测图纸(米)

基础知识%>%
  ggplot图(原子发射光谱(年=条件,x个=响应))+
  统计间隔(_I)(原子发射光谱(x个=预测),数据=preds)+
  统计点间隔(原子发射光谱(x个=.epred),数据=意味着,.宽度= c(c)(.66, .95),位置= 位置_预算(年= -0.3))+
  地理点()+
  缩放彩色打印机()

克鲁斯克式的后验预测

上述后验预测方法整合了提供单一后验预测的参数不确定性分布。约翰·克鲁斯克在他的书中经常使用的另一种方法正在执行贝叶斯数据分析,试图显示预测不确定性和参数不确定性同时显示后验所暗示的几个可能的预测分布。

我们可以很容易地通过要求分配后验所暗示的给定预测的参数。我们会的通过设置dpar=c(“mu”,“sigma”)在里面添加_预先绘制()。而不是指定参数显式地,您也可以只设置dpar=真获得抽奖根据模型中的所有分布参数,这将适用于brms支持的任何响应分发。然后,我们可以选择一个小绘制次数使用示例_图纸()然后使用ggdist::stat_slab()可视化每个预测的值所隐含的分布西格玛:

基础知识%>%
  数据网格(条件)%>%
  添加_预先绘制(m,数据保护器= c(c)(“mu”,“西格玛”))%>%
  示例_图纸(30)%>%
  ggplot图(原子发射光谱(年=条件))+
  统计实验室(原子发射光谱(xdist(扩展列表)= 异常(_N)(μ,σ)),
    slab_color(板条_颜色)= “灰色65”,阿尔法= 1/10,填充= 不适用
)+
  地理点(原子发射光谱(x个=响应),数据=ABC,形状= 21,填充= “#9ECAE1”,尺寸= 2)

我们甚至可以结合克鲁斯克式的预测图半眼分布显示后部平均值:

基础知识%>%
  数据网格(条件)%>%
  添加_预先绘制(米,数据保护器= c(c)(“亩”,“西格玛”))%>%
  ggplot图(原子发射光谱(x个=条件))+
  统计实验室(原子发射光谱(艾迪斯= 异常(_N)(μ,σ)),
    slab_color(板条_颜色)= “灰色65”,阿尔法= 1/10,填充= 不适用,数据=.%>% 示例_图纸(30),刻度=.5
)+
  统计_半眼(原子发射光谱(年=.epred),侧面= “底部”,比例尺=.5)+
  地理点(原子发射光谱(年=响应),数据=ABC,形状= 21,填充= “#9ECAE1”,尺寸= 2,位置= 位置_预算(x个= -.2))

拟合/预测曲线

为了演示绘制具有不确定性的拟合曲线,让我们拟合略显幼稚的模型地铁车厢数据集:

m_mpg(英里/加仑)= 商业风险管理(
英里/加仑~马力*气缸,
  数据=地铁,
  
  文件= “型号/tidy-brms_m_mpg.rds”  #缓存模型(可以删除)
)

我们可以用概率带绘制拟合曲线:

地铁车厢%>%
  分组方式(_B)(气缸)%>%
  数据网格(马力= 序列范围(_R)(马力,n个= 51))%>%
  添加_预先绘制(百万加仑)%>%
  ggplot图(原子发射光谱(x个=马力,年=英里/加仑,颜色= 命令(气缸))+
  stat_lineribbon状态(原子发射光谱(年=.epred))+
  地理点(数据=mtcars)+
  规模灌装机(调色板= “灰色”)+
  缩放彩色打印机(调色板= “设置2”)

或者我们可以抽样合理数量的拟合线(比如100条)覆盖它们:

地铁车厢%>%
  分组方式(_B)(气缸)%>%
  数据网格(马力= 序列范围(_R)(马力,n个= 101))%>%
  #注释:这显示了使用ndraws在add_epred_draws()中进行子采样
  #只有当你计划制作意大利面条等时,才可以这样做。
  #绝不要对小样本进行二次采样,以绘制间隔、密度等。
  添加_预先绘制(m_mpg,ndraws公司= 100)%>%
  ggplot图(原子发射光谱(x个=马力,年=英里/加仑,颜色= 命令(气缸))+
  地理线(原子发射光谱(年=.epred、,组= 粘贴(气缸拉伸),阿尔法=.1)+
  地理点(数据=mtcars)+
  缩放彩色打印机(调色板= “深色2”)

或者我们可以创建动画假设结果图拟合线的数量:

设置种子(123456)
#注释:使用少量绘图保留此示例
#小,但实际上你可能想要50或100
ndraws公司= 20

第页=地铁车厢%>%
  分组方式(_B)(气缸)%>%
  数据网格(马力= 序列范围(_R)(马力,n个= 101))%>%
  添加_预先绘制(m_mpg,ndraws公司=ndraws)%>%
  ggplot图(原子发射光谱(x个=马力,年=英里/加仑,颜色= 命令(气缸))+
  地理线(原子发射光谱(年=.epred、,组= 粘贴(气缸拉伸))+
  地理点(数据=mtcars)+
  缩放彩色打印机(调色板= “深色2”)+
  过渡状态(.绘制,0,1)+
  阴影_标记(未来= 真的,颜色= “灰色50”,阿尔法= 1/20)

使有生气(第页,n帧=ndraws,每秒= 2.5,宽度= 432,高度= 288,单位= “像素”,资源= 96,开发= “ragg_png”)

或者我们可以绘制后验预测(而不是平均值)。为了这个我们还将使用的示例阿尔法让它更容易看到重叠带:

地铁车厢%>%
  分组方式(_B)(气缸)%>%
  数据网格(马力= 序列范围(_R)(马力,n个= 101))%>%
  添加预测图纸(百万加仑)%>%
  ggplot图(原子发射光谱(x个=马力,年=英里/加仑,颜色= 命令(气缸),填充= 命令(气缸))+
  stat_lineribbon状态(原子发射光谱(年=预测),.宽度= c(c)(.95, .80, .50),阿尔法= 1/4)+
  地理点(数据=mtcars)+
  规模灌装机(调色板= “设置2”)+
  缩放彩色打印机(调色板= “深色2”)

这很难通过群体来判断,所以最好是切面分成多个地块。幸运的是,由于我们使用ggplot功能内置于:

地铁车厢%>%
  分组方式(_B)(气缸)%>%
  数据网格(马力= 序列范围(_R)(马力,n个= 101))%>%
  添加预测图纸(百万加仑)%>%
  ggplot图(原子发射光谱(x个=马力,年=英里/加仑)+
  stat_lineribbon状态(原子发射光谱(年=预测),.宽度= c(c)(.99, .95, .8, .5),颜色= 酿酒商.pal(5,“蓝色”)[[5]])+
  地理点(数据=mtcars)+
  规模灌装机()+
  面_网格(.~气缸,空间= “免费_x”,天平= “免费_x”)

提取分布回归参数

brms::brm()还允许我们为以下对象建立子模型响应分布参数位置(例如,平均值)。例如,我们可以允许方差参数,例如标准差,也是预测因子的函数。

这种方法在非恒定方差的情况下很有帮助(也打电话异方差喜欢通过模糊处理的人拉丁语)。例如,想象两组,每组的平均反应不同和方差:

设置种子(1234)
AB公司= 易怒的(
  组= 代表(c(c)(“a”,“b”),每个= 20),
  响应= rnorm公司(40,平均值= 代表(c(c)(1,5),每个= 20),标准偏差= 代表(c(c)(1,),每个= 20))
)

AB公司%>%
  ggplot图(原子发射光谱(x个=响应,年=组))+
  地理点()

下面是一个模型,它让平均值和标准偏差属于响应依赖:

m实验室= 商业风险管理(
  高炉(
响应~组,
西格玛~
),
  数据=AB公司,
  
  文件= “型号/tidy-brms_m_ab.rds”  #缓存模型(可以删除)
)

我们可以绘制平均值的后验分布响应与后验预测区间和数据:

网格=AB公司%>%
  数据网格(组)

方法=网格%>%
  添加_预先绘制(m_ab)

预放电=网格%>%
  添加预测图纸(m_ab)

AB公司%>%
  ggplot图(原子发射光谱(x个=响应,年=组))+
  统计_半眼(原子发射光谱(x个=.epred),刻度= 0.6,位置= 位置_预算(年= 0.175),数据=手段)+
  统计间隔(_I)(原子发射光谱(x个=预测),数据=preds)+
  地理点(数据=阿联酋)+
  缩放彩色打印机()

这显示了每组平均值的后验值(黑色间隔和密度图)和后验预测区间(蓝色)。

组内预测区间b条大于英寸因为模型符合不同的标准每组的偏差。我们可以看到相应的分布参数,西格玛,通过提取更改使用数据保护器的参数添加_预先绘制():

网格%>%
  添加_预先绘制(m_ab,数据保护器= 真的)%>%
  ggplot图(原子发射光谱(x个=西格玛,年=组))+
  统计_半眼()+
  地理vline(辛特西普= 0,线型= “虚线”)

通过设置dpar=真,所有分布参数作为附加列添加到添加_预先绘制(); 如果您只需要特定参数,您可以指定它(或只指定所需参数的列表)。上述模型,dpar=真等于dpar=列表(“mu”,“sigma”).

比较因子的级别

如果我们想比较每个条件的平均值,比较级别()有助于比较某个因素的不同层次的一些变量。默认情况下,它计算所有成对差异。

让我们演示一下比较级别()具有ggdist::stat_halfeye().我们还将通过以下方式重新订购差异:

%>%
  展开_绘制(r_条件[条件,])%>%
  比较级别(r_ condition,由=条件)%>%
  取消分组()%>%
  突变(条件= 重新排序(条件,r_condition))%>%
  ggplot图(原子发射光谱(年=条件,x个=r_条件)+
  统计_半眼()+
  地理vline(辛特西普= 0,线型= “虚线”)

顺序模型

这个后_epred()序数和函数brms中的多项式回归模型返回多个变量每场平局:每个结果类别一场(与之相反rstanarm::stan_polr()模型,它从潜在线性预测)。哲学河豚是到整理模型输出的任何格式,以便与之保持一致哲学,适用于序数和多项式业务风险管理系统模型,添加_预先绘制()添加一个名为.类别和包含变量的单独行针对每个绘制和预测器输出每个类别。

带连续预测器的序数模型

我们将使用地铁车厢预测的数据集给定汽车里程数的汽车气缸数(单位:英里/加仑)。虽然这有点倒退因果关系(大概是气缸数导致里程(如果有的话),这并不意味着这不是一个很好的预测任务(我可能会告诉某人对汽车的MPG有一定的了解,他们可以做得很合理善于猜测发动机中的气缸数)。

在拟合模型之前,让我们通过将气缸列一个有序因子(默认情况下,它只是一个编号):

mtcars_清洁=地铁车厢%>%
  突变(气缸= 命令(气缸)

(mtcars_clean)
英里/加仑 气缸 显示 马力 乏味的 重量 qsec(秒) 齿轮 碳水化合物
马自达RX4 21 6 160 110 3.90 2.620 16.46 0 1 4 4
马自达RX4旅行车 21 6 160 110 3.90 2.875 17.02 0 1 4 4
达特桑710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
大黄蜂4号驱动器 21.4 6 258 110 3.08 3.215 19.44 1 0 1
大黄蜂运动会 18.7 8 360 175 3.15 3.440 17.02 0 0 2
勇敢的 18.1 6 225 105 2.76 3.460 20.22 1 0 1

然后我们将拟合一个序数回归模型:

m气缸= 商业风险管理(
气缸~英里/加仑,
  数据=mtcars_清洁,
  家庭=累计,
  种子= 58393,
  
  文件= “型号/tidy-brms_m_cyl.rds”  #缓存模型(可以删除)
)

添加_预先绘制()将包括一个.类别列,和.epred(.epred)将包含来自后部的抽签响应属于该类别的概率分布。例如,以下是数据集中第一行的拟合度:

易怒的(英里/加仑= 21)%>%
  添加_预先绘制(m_cyl)%>%
  中天_qi(.epred)
英里/加仑 .行 .类别 .epred(.epred) .下部 .上部 .宽度 .间隔
21 1 4 0.3462689 0.0951898 0.7103225 0.95 中值的
21 1 6 0.6198780 0.2634698 0.8916873 0.95 中值的
21 1 8 0.0135699 0.0002870 0.1237972 0.95 中值的

注:对于.类别变量以保留其原始值必须使用的因子级别名称业务风险管理系统大于或等同于版本2.15.9。

我们可以根据预测的概率绘制拟合线数据集:

数据块=mtcars_清洁%>%
  ggplot图(原子发射光谱(x个=英里/加仑,年=气缸,颜色=气缸)+
  地理点()+
  缩放彩色打印机(调色板= “深色2”,姓名= “气缸”)

fit插槽=mtcars_清洁%>%
  数据网格(英里/加仑= 序列范围(_R)(英里/加仑,n个= 101))%>%
  添加_预先绘制(m气缸,价值= “P(气缸|mpg)”,类别= “气缸”)%>%
  ggplot图(原子发射光谱(x个=英里/加仑,年= `P(气缸|mpg)`,颜色=气缸)+
  stat_lineribbon状态(原子发射光谱(填充=气缸),阿尔法= 1/5)+
  缩放彩色打印机(调色板= “深色2”)+
  规模灌装机(调色板= “深色2”)

绘图网格(ncol公司= 1,对齐= “v”,
数据块,
配件_批次
)

上面的显示无法让您看到P(气缸|mpg)对于不同的值气缸位于的特定值英里/加仑例如,在后面的位置P(气缸=6|mpg=20)很高,P(气缸=4|mpg=20)P(气缸=8|mpg=20)必须为低(因为这些必须加起来为1)。

查看这种相关性的一种方法可能是假设结果图(HOP)仅适用于拟合线,将其从色带上“分离”(另一种选择是在线路信号群顶部使用HOP,如在本文档前面进行了演示)。通过使用动画,您可以看看这些线是如何串联或相互对立的,揭示了它们是如何相互关联的一些模式:

#注释:使用少量绘图保留此示例
#小,但实际上你可能想要50或100
ndraws公司= 20

第页=mtcars_清洁%>%
  数据网格(英里/加仑= 序列范围(_R)(英里/加仑,n个= 101))%>%
  添加_预先绘制(m气缸,价值= “P(气缸|mpg)”,类别= “气缸”)%>%
  ggplot图(原子发射光谱(x个=英里/加仑,年= `P(气缸|mpg)`,颜色=气缸)+
  #我们从statlineribbon的数据中删除了`.draw`列,以便使用相同的色带
  #在每一帧上绘制(因为我们使用.draw来确定下面的变换)
  stat_lineribbon状态(原子发射光谱(填充=气缸),阿尔法= 1/5,颜色= 不适用,数据=.%>% 选择(-.绘制)+
  #我们使用sampledraws在geomline级别进行子采样(而不是对完整数据集进行子采样
  #与前面的HOP示例一样),因为我们需要上面stat_lineribbon的全套抽签
  地理线(原子发射光谱(组= 粘贴(.draw,气缸)),线宽= 1,数据=.%>% 示例_图纸(ndraws))+
  缩放彩色打印机(调色板= “深色2”)+
  规模灌装机(调色板= “深色2”)+
  手动转换(.绘制)

使有生气(第页,n帧=ndraws,fps(英尺/秒)= 2.5,宽度= 576,高度= 192,单位= “像素”,资源= 96,开发= “ragg_png”)

注意这些线是如何一起移动的,以及它们是如何上下移动的一起或对立。我们可以在上图中的x位置(例如,英里/加仑=20)然后看使用散点图矩阵确定它们之间的相关性:

易怒的(英里/加仑= 20)%>%
  添加_预先绘制(m气缸,价值= “P(气缸|mpg=20)”,类别= “气缸”)%>%
  取消分组()%>%
  选择(.拉伸,气缸,`P(气缸|mpg=20)`)%>%
  gather_pairs(聚会_聚会)(气缸,`P(气缸|mpg=20)`,三角形= “两者”)%>%
  滤波器(.行!=.col)%>%
  ggplot图(原子发射光谱(.x,.y))+
  地理点(阿尔法= 1/50)+
  面_网格(.行~.col)+
  伊拉布(“P(cyl=row | mpg=20)”)+
  xlab公司(“P(cyl=col | mpg=20)”)

当谈论序数分布的平均值时没有道理,在这种特殊情况下,人们可能会认为根据每加仑汽油的英里数,预计汽车的气缸数为有意义的数量。我们可以为给定每英里特定里程的汽车平均气缸数加仑,如下所示:

\[\textrm{E}[\textrm{cyl}|\textrm{mpg}=m]=\sum_{c\in\{4,6,8\}}c\cdot\textrm{P}(\textrm{cyl}=c|\textrm{mpg}=m)\]我们可以使用上述公式推导出一个后验公式分配\(\textrm{E}[\textrm{cyl}|\textrm}mpg}=m]\)来自模型。该模型为我们提供了\(\textrm{P}(\textrma{cyl}=c|\textrm{mpg}=m):什么时候英里/加仑=\(米\),的响应标度线性预测器(.epred(.epred)来自的列添加_预先绘制())的气缸(又名.类别) =\(c)\(\textrm{P}(\textrma{cyl}=c|\textrm{mpg}=m).因此,我们可以在.绘制然后使用总结计算期望值:

标签数据函数=.%>% 
  取消分组()%>%
  滤波器(英里/加仑== 分位数(英里/加仑。47))%>%
  summary_if(总结_if)(即数字,平均值)

带平均值的数据包=mtcars_清洁%>%
  数据网格(英里/加仑= 序列范围(_R)(英里/加仑,n个= 101))%>%
  #注释:这显示了使用ndraws在add_epred_draws()中进行子采样
  #只有当你计划制作意大利面条等时,才可以这样做。
  #绝不要对小样本进行二次采样,以绘制间隔、密度等。
  添加_预先绘制(m气缸,价值= “P(气缸|mpg)”,类别= “气缸”,ndraws公司= 100)%>%
  分组方式(_B)(mpg,.draw)%>%
  #计算预期气缸值
  突变(气缸= as.数字(as字符(气缸))%>%
  总结(气缸= 总和(气缸* `P(气缸|mpg)`),.个组= “下降”)%>%
  ggplot图(原子发射光谱(x个=英里/加仑,年=气缸)+
  地理线(原子发射光谱(组=.绘制),阿尔法= 5/100)+
  地理点(原子发射光谱(年= as.数字(as字符(气缸)),填充=气缸),数据=mtcars_清洁,形状= 21,尺寸= 2)+
  地理文本(原子发射光谱(x个=英里/加仑+ 4),标签= “E[cyl|mpg]”,数据=标签数据函数,他只是= 0)+
  地理段(原子发射光谱(日元=气缸,X射线=英里/加仑+ 3.9),数据=标签数据函数)+
  规模灌装机(调色板= “设置2”,姓名= “气缸”)

绘图_网格(ncol公司= 1,对齐= “v”,
带有平均值的数据块,
fit插槽
)

现在让我们做一些后验预测检查:做后验预测看起来像数据?为此,我们将在相同的值英里/加仑如原件所示数据集(灰色圆圈),并用观察到的数据(彩色圆圈):

mtcars_清洁%>%
  #我们在这里使用“select”而不是“datagrid”,因为我们想进行后验预测
  #与原始数据中的观测结果完全相同
  选择(英里/加仑)%>%
  添加预测图纸(m气缸,种子= 1234)%>%
  #恢复原始因子标签
  突变(气缸= 水平(mtcars_清洁$cyl)[预测])%>%
  ggplot图(原子发射光谱(x个=英里/加仑,年=气缸)+
  地理计数(颜色= “灰色75”)+
  地理点(原子发射光谱(填充=气缸),数据=mtcars_清洁,形状= 21,尺寸= 2)+
  规模灌装机(调色板= “深色2”)+
  地理标签(
    数据=.%>% 取消分组()%>% 滤波器(气缸== "8")%>% 滤波器(英里/加仑== 最大值(英里/加仑)%>%数字播放器::(1),
    标签= “后验预测”,xlim公司= c(c)(26,不适用),伊林= c(c)(不适用,2.8),点.添加= 0.3,
    标签.尺寸= 不适用,颜色= “灰色50”,分段.颜色= “灰色75”
)+
  地理标签(
    数据=mtcars_清洁%>% 滤波器(气缸== "6")%>% 滤波器(英里/加仑== 最大值(英里/加仑)%>%数字播放器::(1),
    标签= “观测数据”,xlim公司= c(c)(26,不适用),伊林= c(c)(2.2,不适用),点.添加= 0.2,
    标签.尺寸= 不适用,分段.颜色= “灰色35”
)

这个看起来不错。让我们用另一个典型的后部检查预测检验图:响应的许多模拟分布(气缸)相对于观察到的响应分布。对于连续响应变量,通常使用密度情节;在这里,我们将绘制每个箱子中的后验预测数作为线图,因为响应变量是离散的:

mtcars_清洁%>%
  选择(英里/加仑)%>%
  添加预测图纸(m气缸,ndraws公司= 100,种子= 12345)%>%
  #恢复原始因子标签
  突变(气缸= 水平(mtcars_清洁$cyl)[预测])%>%
  ggplot图(原子发射光谱(x个=气缸)+
  统计_计数(原子发射光谱(组= 不适用),地理= “线路”,数据=mtcars_清洁,颜色= “红色”,线宽= ,阿尔法=.5)+
  统计_计数(原子发射光谱(组=.绘制),地理= “线路”,位置= “身份”,阿尔法=.05)+
  地理标签(数据= 数据帧(气缸= "4"),年= 9.5,标签= “后面\n个预测”,
    他只是= 1,颜色= “灰色50”,线条高度= 1,标签.尺寸= 不适用)+
  地理标签(数据= 数据帧(气缸= "8"),年= 14,标签= “观察到\n个数据”,
    他只是= 0,颜色= “红色”,线条高度= 1,标签.尺寸= 不适用)

这看起来也不错。

另一种看待这些后验预测的方法可能是散点图矩阵。gather_pairs()很容易做到生成适合创建自定义的长格式数据帧散点图矩阵(或真正的任意矩阵式小倍数plot)在ggplot中使用ggplot2::面网格():

设置种子(12345)

mtcars_清洁%>%
  选择(英里/加仑)%>%
  添加预测图纸(m_cyl)%>%
  #恢复原始因子标签。必须先取消分组,以便
  #在所有组中以相同的方式创建因子;这是一个变通办法
  #因为brms不再返回标记的预测(希望是
  #已修复,则不再需要此功能)
  取消分组()%>%
  突变(气缸= 命令(水平(mtcars_清洁$cyl)[预测],水平(mtcars_清洁$气缸))%>%
  #need.drop=FALSE以确保0计数不被丢弃
  分组方式(_B)(.绘制,.下降= 错误的)%>%
  计数(气缸)%>%
  gather_pairs(聚会_聚会)(气缸,n)%>%
  ggplot图(原子发射光谱(.x,.y))+
  地理计数(颜色= “灰色75”)+
  地理点(数据=mtcars_清洁%>% 计数(气缸)%>% gather_pairs(聚会_聚会)(气缸,n),颜色= “红色”)+
  面_网格(变量(.行),变量(.col))+
  xlab公司(“cyl=col的观察次数”)+
  伊拉布(“cyl=行的观测数”)

具有分类预测器的有序模型

下面是一个带有分类预测因子的序数模型:

数据(食管)
m_esoph_brm(电子邮件)= 商业风险管理(
托布普~年龄gp,
  数据=食管,
  家庭= 累计(),

  文件= “型号/tidy-brms_m_esoph_brm.rds”  
)

然后我们可以绘制每个结果类别的预测概率在预测的每个级别内:

食管%>%
  数据网格(年龄)%>%
  添加_预先绘制(m_esoph_brm,数据保护器= 真的,类别= “托布普”)%>%
  ggplot图(原子发射光谱(x个=年龄gp,年=.epred、,颜色=tobgp))+
  统计点间隔(位置= 位置_对象(宽度=.4))+
  缩放_大小_连续(指南= “无”)+
  刻度-颜色-手动(值= 酿酒商.pal(6,“蓝色”)[-c(c)(1,2)])

很难看到上述图中类别的变化;让我们试着做一些能更好地说明每个分布的要点的事情年份:

食管裂孔=食管%>%
  数据网格(年龄)%>%
  添加_预先绘制(m_esoph_brm,类别= “托布普”)%>%
  ggplot图(原子发射光谱(x个=.epred、,年=tobgp))+
  坐标_自流(展开= 错误的)+
  面_网格(.~年龄gp,交换机= “x”)+
  主题_经典()+
  主题(带状背景= 元素_blank(),条带放置= “外部”)+
  gg标题(“P(烟草消费类别|年龄组)”)+
  xlab公司(“年龄组”)

食管裂孔+
  统计摘要(有趣=中值的,地理= “酒吧”,填充= “灰色65”,宽度= 1,颜色= “白色”)+
  统计点间隔()

这种情况下的条形图可能会产生错误的精确度,因此我们也可以尝试CCDF条形图:

食管裂孔+
  统计_ccdfinterval()+
  expand_limits(扩展限制)(x个= 0)#确保条变为0

该输出应与相应的m_esoph_rs中的模型小插曲(“整洁的rstanarm”)(对不同的先验取模)brms为我们生产它所做的工作比圣塔那主义做。