Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot method for class brmsprior #694

Closed
Ax3man opened this issue Jun 28, 2019 · 7 comments
Closed

Plot method for class brmsprior #694

Ax3man opened this issue Jun 28, 2019 · 7 comments
Labels

Comments

@Ax3man
Copy link

Ax3man commented Jun 28, 2019

I think it is very useful, and educational, to plot prior distributions. To that end, a useful addition to brms could be to have a plot.brmsprior method, so one can simply do e.g.:

p <- prior(normal(0, 2))
plot(p)

Or even multiple plots (or small multiples) for all priors:

p <- get_prior(qsec ~ hp + (1 + hp | cyl), mtcars)
plot(p)

If you'd be interested I could try to have a look at an implementation, although it may take me a couple of months to get around to it.

@paul-buerkner
Copy link
Owner

I like the idea and will think of a good implmentation.

@paul-buerkner
Copy link
Owner

@mjskay how far is the prior plotting feature in tidybayes developed? Perhaps a separate brms implementation may not even be required.

@mjskay
Copy link

mjskay commented Feb 1, 2020

Hmm good question. Depends on how low-level you want to be writing code. E.g. if you take this model from the "tidy-brms" vignette in tidybayes:

m = brm(response ~ (1|condition), data = ABC, control = list(adapt_delta = .99),
  prior = c(
    prior(normal(0, 1), class = Intercept),
    prior(student_t(3, 0, 1), class = sd),
    prior(student_t(3, 0, 1), class = sigma)
  ))

You can do something like this:

m %>% 
  prior_summary() %>% 
  parse_dist(prior)
               prior     class      coef     group resp dpar nlpar bound     .dist   .args
1       normal(0, 1) Intercept                                                norm    0, 1
2 student_t(3, 0, 1)        sd                                           student_t 3, 0, 1
3                           sd           condition                            <NA>      NA
4                           sd Intercept condition                            <NA>      NA
5 student_t(3, 0, 1)     sigma                                           student_t 3, 0, 1

That function adds on the .dist and .args columns and also attempts to translate stan distributions into ones that R recognizes (so here normal -> norm and student_t -> student_t, using the implementation in brms). To plot it then you just have to use one of the stat_dist_... geoms:

m %>% 
  prior_summary() %>% 
  parse_dist(prior) %>% 
  ggplot(aes(y = class, dist = .dist, args = .args)) + 
  stat_dist_halfeyeh()

image

Of course, there's some issues here:

  • I'm not sure I have all the stan -> R distribution translations, but I plan to include as many as possible (this is why tidybayes now has lkjcorr_marginal)
  • Speaking of LKJ distributions, because the prior summary does not include the dimensions of the correlation matrix, an extra step with tidybayes::marginalize_lkjcorr() is necessary for the user to specify the dimension of the matrix to visualize those priors (see that page for an example).
  • You probably noticed it doesn't handle truncation yet. Eventually I plan to add that, which should make the sigma and sd priors respect their bounds.

I think the approach above is reasonable for a lower-level approach like in tidybayes so that people could build custom plots of priors; the expectation would be that they might have their own desires/needs as far as how they want to set up the chart. But for a quick summary it might be valuable to have something that does more automatic mappings of class/coef/group/etc onto some aesthetics and such. Even combining them into single labels as a rough first step:

m %>% 
  prior_summary() %>% 
  mutate(label = pmap_chr(select(., -prior), paste)) %>% 
  parse_dist(prior) %>% 
  ggplot(aes(y = label, dist = .dist, args = .args)) + 
  stat_dist_halfeyeh()

image

Then you could do the small multiples version as well (not sure if unaligned axes are a good idea here, drop the scales = "free_x" if you don't want them...) and add labels for the distribution:

m %>% 
  prior_summary() %>% 
  mutate(label = pmap_chr(select(., -prior), paste)) %>% 
  parse_dist(prior) %>% 
  ggplot(aes(y = 0, dist = .dist, args = .args)) + 
  stat_dist_halfeyeh() + 
  geom_text(aes(label = prior), x = 0, y = .97) + 
  facet_wrap(~ label, scales = "free_x")

image

So I'd say it probably depends on the use case if you think there needs to be something more automatic. Currently I'd say tidybayes has most of the necessary primitives but expects a bit of work from the user.

@paul-buerkner
Copy link
Owner

Nice! This is impressive! I don't think brms needs anything more than this on its own, especially since tidybayes does so much of the hard stuff already. For brms users of this tidybayes feature, please note that you can put any brmsprior object into the call

brmsprior %>% 
  parse_dist(prior)

and it will work. That is, the model does not need to be fitted in order for priors to be plotted.

@mjskay
Copy link

mjskay commented Feb 2, 2020

Cool, will do!

@paul-buerkner
Copy link
Owner

paul-buerkner commented Feb 2, 2020 via email

@Ax3man
Copy link
Author

Ax3man commented Feb 4, 2020

I'm closing this since this functionality will live in tidybayes. Thanks to you both!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants