Repository navigation
print() fails for estimate_means() / estimate_contrasts() on Wiener and RT-choice models #680
Description
Problem
For a model that insight::model_info() flags as is_wiener (brms
wiener()) or is_rtchoice (e.g. the cogmod choice families), every
print() method takes the drift-diffusion branch and calls
.print_drift_diffusion(). That function splits the table by its Component
column, but only predictions of the response have one (estimate_prediction()
returns an rt and a response block). Estimates of a distributional
parameter, such as predict = "mu" or predict = "bs", have no Component.
They are computed correctly, and then printing them fails.
Reprex
library(brms)
options(wiener_backend = "rtdists") # for posterior_predict(); RWiener works too
set.seed(1)
sim <- rbind(
rtdists::rdiffusion(150, a = 1.5, v = 0.5, t0 = 0.3, z = 0.75),
rtdists::rdiffusion(150, a = 1.5, v = 1.5, t0 = 0.3, z = 0.75)
)
d <- data.frame(
x = rep(c("a", "b"), each = 150),
rt = sim$rt,
resp = as.integer(sim$response == "upper")
)
m <- brm(bf(rt | dec(resp) ~ x), data = d, family = wiener(),
chains = 1, iter = 400, refresh = 0, seed = 1)
est <- modelbased::estimate_means(m, by = "x", predict = "mu")
as.data.frame(est) # values are fine
est
#> Error in `$<-.data.frame`(`*tmp*`, "Component", value = ...) :
#> replacement has 0 rows, data has 2
modelbased::estimate_contrasts(m, contrast = "x", predict = "mu")
#> Error in `$<-.data.frame`(`*tmp*`, "Component", value = ...) :
#> replacement has 0 rows, data has 1The same happens with predict = "bs", and on cogmod::cogmod_ddm() fits
(which model_info() flags is_rtchoice), including estimate_means() with
no predict.
Cause
print.estimate_contrasts(), R/print.R (L110 on main). Seven other print
methods are aliases of it (print.estimate_means, print.estimate_slopes,
print.summary_estimate_slopes, print.estimate_smooth,
print.estimate_predicted, print.visualisation_matrix,
print.estimate_grouplevel, L130-148), so they all fail the same way.
if (isTRUE(attr$model_info$is_wiener) || isTRUE(attr$model_info$is_rtchoice)) {
out <- .print_drift_diffusion(out, select, ...)Suggested fix
Take that branch only when there is something to split:
if ((isTRUE(attr$model_info$is_wiener) || isTRUE(attr$model_info$is_rtchoice)) &&
"Component" %in% colnames(x)) {I tested this patch on the model above. estimate_means(predict = "bs") and
estimate_contrasts(predict = "mu") print the regular table, and
estimate_prediction() still prints its two sub-tables (rt, response).
Related edge case
.print_drift_diffusion() also fails when only one component is present,
for instance after subsetting:
head(modelbased::estimate_prediction(m), 2) # both rows are from the "rt" block
#> Error in x[[i]] <- value :
#> attempt to select less than one element in OneIndexWith a single component, setdiff(names(out), i) is character(0), so
out[[i]][[setdiff(names(out), i)]] <- NULL fails (L202 on main). A guard
fixes it:
other <- setdiff(names(out), i)
if (length(other)) out[[i]][[other]] <- NULLVersions
R 4.5.3, brms 2.23.1, insight 1.5.4.2, modelbased 0.17.0.6. The code above is
unchanged on main (0.17.0.13).
Activity