mjskay / tidybayes

Bayesian analysis + tidy data + geoms (R package)
http://mjskay.github.io/tidybayes
GNU General Public License v3.0
718 stars 59 forks source link

How to dynamically define variable name in gather_draws? #166

Closed Aorus42 closed 5 years ago

Aorus42 commented 5 years ago

Using a subset of the list from get_variables(fit), group_vars, I'd like to dynamically define the variable name in gather_draws to iteratively go through all the group-level terms in my mixed effects model (defined in brms). However, I haven't been able to figure out how to do so, despite trying the tricks used in dplyr for dynamic variable names (e.g., using !! to unquote a symbol with backticks).

For example, this doesn't work:

i = 1
param_name = sym(paste0('r_', group_vars[[i]], '[lvl,]'))
pred_delta = fit %>% 
  gather_draws(!!param_name)

throwing the error

Error in spread_draws_long_(model, variable_names, dimension_names, regex = regex,  : 
  No variables found matching spec: c(r_Patient\[lvl\,\])

where "Patient" is one of the group-level factors in my model. I also tried some variations using the regex=TRUE argument in gather_draws, to no avail. Any help is much appreciated!

mjskay commented 5 years ago

Ah, good question!

The issue is that this:

i = 1
param_name = sym(paste0('r_', group_vars[[i]], '[lvl,]'))

Results in a single symbol with the name "r_Patient[lvl,]", as opposed to an expression with a symbol named "r_Patient" being subscripted with [lvl,]. You can see this by inspecting param_name:

str(param_name)
## symbol r_Patient[lvl,]

There are two ways to solve this. One is to build up an expression instead of a symbol:

i = 1
param_name = sym(paste0('r_', group_vars[[i]])
param_expr = expr((!!param_name)[lvl,])

Then param_expr is an unevaluated expression containing the symbol r_Patient being subscripted with [lvl,]:

str(param_expr)
##  language r_Patient[lvl, ]

Then you can use it in gather_draws:

pred_delta = fit %>% 
  gather_draws(!!param_expr)

Or if you constructed a list of expressions like this, say param_exprs, and you wanted to gather all of them at once, you could use !!! (three exclamation points):

pred_delta = fit %>% 
  gather_draws(!!!param_exprs)

The second way, if you are just doing one at a time, is to skip the creation of the intermediate param_expr variable and do the unquoting operation directly in gather_draws:

i = 1
param_name = sym(paste0('r_', group_vars[[i]])
pred_delta = fit %>% 
  gather_draws((!!param_name)[lvl,])

Let me know if that works / makes sense, or if you have other questions. Quasi-quotation can be a real pain to reason about!

Aorus42 commented 5 years ago

That did the trick, thanks!

chqq365 commented 1 year ago

very helpful post