【问题标题】:Plotting posterior parameter estimates from multiple models with bayesplot使用bayesplot绘制来自多个模型的后验参数估计
【发布时间】:2018-10-18 13:54:35
【问题描述】:

我正在使用出色的绘图库 bayesplot 来可视化我使用 rstanarm 估计的模型的后验概率区间。我想通过将系数的后验间隔放到同一个图上来以图形方式比较来自不同模型的绘图。

例如,想象一下,对于两个不同的模型,我有 1000 个来自后验的三个参数beta1, beta2, beta3

# load the plotting library
library(bayesplot)
#> This is bayesplot version 1.6.0
#> - Online documentation and vignettes at mc-stan.org/bayesplot
#> - bayesplot theme set to bayesplot::theme_default()
#>    * Does _not_ affect other ggplot2 plots
#>    * See ?bayesplot_theme_set for details on theme setting
library(ggplot2)

# generate fake posterior draws from model1
fdata <- matrix(rnorm(1000 * 3), ncol = 3)
colnames(fdata) <- c('beta1', 'beta2', 'beta3')

# fake posterior draws from model 2
fdata2 <- matrix(rnorm(1000 * 3, 1, 2), ncol = 3)
colnames(fdata2) <- c('beta1', 'beta2', 'beta3')

Bayesplot 为单个模型绘制提供了出色的可视化效果,它是 ggplot2 的“底层”,所以我可以随意自定义:

# a nice plot of 1
color_scheme_set("orange")
mcmc_intervals(fdata) + theme_minimal() + ggtitle("Model 1")

# a nice plot of 2
color_scheme_set("blue")
mcmc_intervals(fdata2) + ggtitle("Model 2")

但我想要实现的是将这两个模型一起绘制在同一个图上,这样对于每个系数我都有两个区间,并且可以通过将颜色映射到模型来区分哪个区间。但是我无法弄清楚如何做到这一点。一些不起作用的东西:

# doesnt work
mcmc_intervals(fdata) + mcmc_intervals(fdata2)
#> Error: Don't know how to add mcmc_intervals(fdata2) to a plot

# appears to pool
mcmc_intervals(list(fdata, fdata2))

关于如何做到这一点的任何想法?或者如何在给定后验矩阵的情况下手动完成?

reprex package (v0.2.1) 于 2018 年 10 月 18 日创建

【问题讨论】:

    标签: r ggplot2 rstan rstanarm


    【解决方案1】:

    所以答案也在这里发布,我已经扩展了来自@Manny T (https://github.com/stan-dev/bayesplot/issues/232) 的链接上的代码

    # simulate having posteriors for two different models each with parameters beta[1],..., beta[4]
    posterior_1 <- matrix(rnorm(4000), 1000, 4)
    posterior_2 <- matrix(rnorm(4000), 1000, 4)
    colnames(posterior_1) <- colnames(posterior_2) <- paste0("beta[", 1:4, "]")
    
    # use bayesplot::mcmc_intervals_data() function to get intervals data in format easy to pass to ggplot
    library(bayesplot)
    combined <- rbind(mcmc_intervals_data(posterior_1), mcmc_intervals_data(posterior_2))
    combined$model <- rep(c("Model 1", "Model 2"), each = ncol(posterior_1))
    
    # make the plot using ggplot 
    library(ggplot2)
    theme_set(bayesplot::theme_default())
    pos <- position_nudge(y = ifelse(combined$model == "Model 2", 0, 0.1))
    ggplot(combined, aes(x = m, y = parameter, color = model)) + 
      geom_linerange(aes(xmin = l, xmax = h), position = pos, size=2)+
      geom_linerange(aes(xmin = ll, xmax = hh), position = pos)+
      geom_point(position = pos, color="black")
    

    如果你像我一样,你会想要 80% 和 90% 的可信区间(而不是 50% 是内部区间)并且可能想要翻转坐标,让我们在 0 处添加一条虚线(模型估计没有变化) .你可以这样做:

    # use bayesplot::mcmc_intervals_data() function to get intervals data in format easy to pass to ggplot
    library(bayesplot)
    combined <- rbind(mcmc_intervals_data(posterior_1,prob=0.8,prob_outer = 0.9), mcmc_intervals_data(posterior_2,prob=0.8,prob_outer = 0.9))
    combined$model <- rep(c("Model 1", "Model 2"), each = ncol(posterior_1))
    
    # make the plot using ggplot 
    library(ggplot2)
    theme_set(bayesplot::theme_default())
    pos <- position_nudge(y = ifelse(combined$model == "Model 2", 0, 0.1))
    ggplot(combined, aes(x = m, y = parameter, color = model)) + 
      geom_linerange(aes(xmin = l, xmax = h), position = pos, size=2)+
      geom_linerange(aes(xmin = ll, xmax = hh), position = pos)+
      geom_point(position = pos, color="black")+
      coord_flip()+
      geom_vline(xintercept=0,linetype="dashed")
    

    关于最后一个需要注意的几点。我添加了prob_outer = 0.9,即使这是默认设置,只是为了展示您如何更改外部可信区间。虚线是用geom_vlinexintercept = 在这里创建的,而不是geom_hlineyintercept = ,因为coord_flip(一切都颠倒了)。所以如果你不翻转轴,你将需要做相反的事情。

    【讨论】:

      【解决方案2】:

      我在 GitHub 上的 bayesplot 页面上提出了这个问题,并得到了回复 (Issue #232)

      【讨论】:

      • 嗨,欢迎来到 SO。对 stan/dev 的很好的跟进。您也可以在此处编辑并放置建议的解决方案,同时保留问题归属。
      • 这很棒。多年来,似乎有很多人关注过这个问题。您为什么不将解决方案粘贴进去,我会接受答案?
      【解决方案3】:

      我花的时间比我想承认的要多,所以不妨把它贴在这里。这是一个包含上述建议的函数(目前)适用于 rstanarm 和 brms 模型对象。

      compare_posteriors <- function(..., dodge_width = 0.5) {
        dots <- rlang::dots_list(..., .named = TRUE)
        draws <- lapply(dots, function(x) {
          if (class(x)[1] == "stanreg") {
              posterior::subset_draws(posterior::as_draws(x$stanfit),
                  variable = names(fixef(x))
              )
          } else if (class(x)[1] == "brmsfit") {
              brm_draws <- posterior::subset_draws(posterior::as_draws(x$fit),
                  variable = paste0("b_", rownames(fixef(x)))
              )
              posterior::variables(brm_draws) <- stringr::str_split(posterior::variables(brm_draws), "_", simplify = T)[, 2]
              posterior::rename_variables(brm_draws, `(Intercept)` = Intercept)
          } else {
              stop(paste0(class(x)[1], " objects not supported."))
          }
        })
        intervals <- lapply(draws, bayesplot::mcmc_intervals_data)
        combined <- dplyr::bind_rows(intervals, .id = "model")
        ggplot(combined, aes(x = m, y = parameter, color = model, group = model)) +
          geom_linerange(aes(xmin = l, xmax = h), size = 2, position = position_dodge(dodge_width)) +
          geom_linerange(aes(xmin = ll, xmax = hh), position = position_dodge(dodge_width)) +
          geom_point(color = "black", position = position_dodge(dodge_width)) +
          geom_vline(xintercept = 0, linetype = "dashed")
      }
      

      用法:

      compare_posteriors(mod1, mod2, mod3)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多