Skip to contents

Density, random generation, and brms custom family for the shifted Log-Student-t distribution - a robust LogNormal. A Log-Student-t distributed decision time is shifted by a non-decision time ndt, and a fixed proportion poutlier of responses is generated by an outlier process instead of by the decision process.

Functions:

  • rcogmod_logstudent(): Simulates random draws.

  • dcogmod_logstudent(): Computes the density (likelihood).

  • pcogmod_logstudent(): Computes the cumulative distribution function (CDF) or survival.

  • cogmod_logstudent(): Creates a brms::custom_family().

  • cogmod_logstudent_stanvars(): Generates the stanvars to pass to brm().

Usage

rcogmod_logstudent(n, mu = -0.7, sigma = 0.4, dof = 5, ndt = 0.2, poutlier = 0)

dcogmod_logstudent(
  x,
  mu = -0.7,
  sigma = 0.4,
  dof = 5,
  ndt = 0.2,
  poutlier = 0,
  log = FALSE
)

pcogmod_logstudent(
  q,
  mu = -0.7,
  sigma = 0.4,
  dof = 5,
  ndt = 0.2,
  poutlier = 0,
  lower.tail = TRUE,
  log.p = FALSE
)

cogmod_logstudent(
  link_mu = "identity",
  link_sigma = "softplus",
  link_dof = "log",
  link_ndt = "log",
  link_poutlier = "logit",
  predict_outliers = FALSE
)

cogmod_logstudent_lpdf_expose()

cogmod_logstudent_stanvars()

log_lik_cogmod_logstudent(i, prep)

posterior_predict_cogmod_logstudent(i, prep, predict_outliers = NULL, ...)

posterior_epred_cogmod_logstudent(prep, predict_outliers = NULL)

Arguments

n

Number of observations. If length(n) > 1, the length is taken to be the number required.

mu

Location of the Student-t on the log scale. Any real value.

sigma

Scale of the Student-t on the log scale. Must be positive.

dof

Degrees of freedom of the Student-t on the log scale. Must be positive. Smaller is heavier-tailed; dof -> Inf is cogmod_lognormal().

ndt

Non-decision time (shift parameter), in seconds. Must be non-negative. Represents time for processes such as stimulus encoding and response execution. Range: [0, Inf).

poutlier

Proportion of responses generated by the outlier process rather than by the decision process. Range: [0, 1]. At poutlier = 0 the distribution reduces to the plain shifted LogNormal.

x

Vector of quantiles (observed reaction times).

log

Logical; if TRUE, probabilities p are given as log(p).

q

Vector of quantiles (reaction times, in seconds).

lower.tail

Logical; if TRUE (default), probabilities are P[X <= q], otherwise P[X > q] - the survival, which is what a right-censored response contributes to the likelihood (see the Censoring section).

log.p

Logical; if TRUE, probabilities p are given as log(p).

Link functions for the parameters.

predict_outliers

Logical; whether posterior_predict() and posterior_epred() should include the outlier component. FALSE (the default) fixes poutlier to zero for prediction, so predictions describe the decision process alone; the likelihood is always the full mixture either way. See with_outliers().

i, prep

For brms' functions to run: index of the observation and a brms preparation object.

...

Additional arguments.

Value

rcogmod_logstudent() returns a numeric vector of n simulated reaction times, in seconds. dcogmod_logstudent() returns the density at each element of x - the log density if log = TRUE - recycled to the length of the longest argument. cogmod_logstudent() returns a brms::custom_family object, to put on a brms::bf() formula. cogmod_logstudent_stanvars() returns a brms::stanvars object holding the family's Stan functions block, to pass to brms::brm(), and cogmod_logstudent_lpdf_expose() compiles that Stan code and returns it as an R function, for checking the density outside of a model. The remaining functions are brms post-processing methods, called by brms rather than directly: log_lik_cogmod_logstudent() returns a numeric vector holding one log-likelihood value per posterior draw for observation i, and posterior_predict_cogmod_logstudent() a draws x 1 matrix of reaction times simulated for observation i. posterior_epred_cogmod_logstudent() returns nothing: the decision time has no finite mean, so it errors rather than report one - summarise posterior_predict() draws instead.

Details

log(RT - ndt) follows a Student-t distribution with location mu, scale sigma and dof degrees of freedom. As dof grows the Student-t becomes the Normal, so cogmod_lognormal() is the dof -> Inf limit: this family varies kurtosis where cogmod_loggamma() varies skew.

dof is what brms::student() calls nu. It is renamed here because cogmod_lnr() already spends nuzero and nuone on drift rates, and because brms recognises the name nu and supplies opinionated defaults for it; dof arrives flat like every other parameter this package defines, so cogmod_priors() simply fills it.

ndt and poutlier mean exactly what they do in cogmod_lognormal(), and with_outliers(), without_outliers(), p_outlier() and cogmod_priors() all work here too. See ?rcogmod_lognormal for why ndt is expressed directly in seconds rather than as a fraction of the fastest observed response, what the outlier component is for, and why its scale is a constant rather than a dpar.

What the heavy tail is for

The outlier component behind poutlier is a half Normal, which by construction cannot explain a slow response: its density at 5 s is effectively zero, so a long right tail is the decision family's own business. cogmod_loggamma()'s shape and cogmod_invgaussian()'s sigmadrift are two ways of providing one. dof is a third, and the most direct: it absorbs slow contaminants into the likelihood rather than into a mixture component. At dof = 5 the probability of a decision time beyond 5 s is about five orders of magnitude larger than the matching LogNormal's.

Two things to know before using it

The mean does not exist, for any finite dof. E[exp(sigma * T)] with T a Student-t diverges because the t has polynomial tails and exp() outruns them - there is no region of the parameter space where this family has an expectation, unlike cogmod_logweibull(), whose mean exists below sigma = 1. posterior_epred() therefore errors rather than returning a number. The median is exact: ndt + exp(mu). For anything else, summarise posterior_predict() draws.

The density is unbounded at ndt. As RT approaches ndt from above the decision density grows like 1 / (t * |log t|^(dof + 1)), where a LogNormal decays to zero. The spike is integrable for every dof > 0, so the posterior stays proper, but the likelihood has no maximum and the prior on ndt is what keeps the sampler off min(RT). This is the same situation as cogmod_loggamma() above sigma * shape = 1, and the reason cogmod_priors() is not optional here.

A Student-t is symmetric on the log scale, so a small dof fattens both tails rather than only the slow one. At dof = 2 some 1.5% of the decision distribution falls below 0.05 s, against a LogNormal's 5e-9 - territory poutlier also claims, so the two trade off. cogmod_priors() centres dof at 6 with 95% of its mass between 1.5 and 24, which keeps the fast-side spike under a tenth of a percent while leaving the slow tail worth having.

References

  • Lange, K. L., Little, R. J. A., & Taylor, J. M. G. (1989). Robust statistical modeling using the t distribution. Journal of the American Statistical Association, 84(408), 881-896. doi:10.2307/2290063

Examples

rts <- rcogmod_logstudent(1000, mu = -0.7, sigma = 0.4, dof = 5,
                          ndt = 0.2, poutlier = 0.02)
hist(rts, breaks = 100, xlab = "RT (s)")


# A heavier tail than the LogNormal it nests, on the slow side...
dcogmod_logstudent(5, dof = 5, ndt = 0.2)
#> [1] 0.0004813849
dcogmod_lognormal(5, ndt = 0.2)
#> [1] 5.628635e-06

# ...and on the fast side too, which is what `poutlier` also covers.
dcogmod_logstudent(0.21, dof = 5, ndt = 0.2)
#> [1] 0.01175141
dcogmod_lognormal(0.21, ndt = 0.2)
#> [1] 4.525335e-12