MyNixOS website logo
Description

Generate 'Stan' Code for Diagnostic Classification Models.

Diagnostic classification models are psychometric models used to categorically estimate respondents mastery, or proficiency, on a set of predefined skills (Bradshaw, 2016, <doi:10.1002/9781118956588.ch13>). Diagnostic models can be estimated with 'Stan'; however, the necessary scripts can be long and complicated. This package automates the creation of 'Stan' scripts for diagnostic classification models. Specify different types of diagnostic models, define prior distributions, and automatically generate the necessary 'Stan' code for estimating the model.

dcmstan dcmstan website

Project Status: Active – The project has reached a stable, usablestate and is being activelydeveloped. lifecycle R packageversion Packagedownloads R-CMD-check codecov pages-build-deployment Signedby License

dcmstan provides functionality to automatically generate Stan code for estimating diagnostic classification models. Using dcmstan, you can:

  • Mix and match different measurement and structural models to specify a diagnostic model with dcm_specify(),
  • Define prior() distributions, and
  • Generate Stan code for the model, given the specifications and priors with stan_code()

dcmstan is used as a backend for generating the Stan code needed to estimate and evaluate with the measr package. If you use measr to estimate your models, you will not need to use dcmstan to generate Stan code yourself.

Installation

You can install the released version of dcmstan from CRAN with:

install.packages("dcmstan")

And the development version from GitHub with:

# install.packages("pak")
pak::pak("r-dcm/dcmstan")

Usage

We can create a specification for a diagnostic model using dcm_specify(), which requires a Q-matrix, the name of the item identifier column in the Q-matrix (optional), and the choice of measurement and structural models.

library(dcmstan)
library(dcmdata)

new_model <- dcm_specify(
  qmatrix = mdm_qmatrix,
  identifier = "item",
  measurement_model = lcdm(),
  structural_model = unconstrained()
)

new_model
#> A loglinear cognitive diagnostic model (LCDM) measuring 1 attributes with 4
#> items.
#> 
#> ℹ Attributes:
#> • "multiplication" (4 items)
#> 
#> ℹ Attribute structure:
#>   Unconstrained
#> 
#> ℹ Prior distributions:
#>   intercept ~ normal(0, 2)
#>   maineffect ~ lognormal(0, 1)
#>   `Vc` ~ dirichlet(1)

We can then generate the Stan code and data list required for estimating the model with {rstan} or {cmdstanr}.

stan_code(new_model)
#> data {
#>   int<lower=1> I;                      // number of items
#>   int<lower=1> R;                      // number of respondents
#>   int<lower=1> N;                      // number of observations
#>   int<lower=1> C;                      // number of classes
#>   array[N] int<lower=1,upper=I> ii;    // item for observation n
#>   array[N] int<lower=1,upper=R> rr;    // respondent for observation n
#>   array[N] int<lower=0,upper=1> y;     // score for observation n
#>   array[R] int<lower=1,upper=N> start; // starting row for respondent R
#>   array[R] int<lower=1,upper=I> num;   // number items for respondent R
#> }
#> parameters {
#>   simplex[C] Vc;
#> 
#>   ////////////////////////////////// item intercepts
#>   real l1_0;
#>   real l2_0;
#>   real l3_0;
#>   real l4_0;
#> 
#>   ////////////////////////////////// item main effects
#>   real<lower=0> l1_11;
#>   real<lower=0> l2_11;
#>   real<lower=0> l3_11;
#>   real<lower=0> l4_11;
#> }
#> transformed parameters {
#>   vector[C] log_Vc = log(Vc);
#>   matrix[I,C] pi;
#> 
#>   ////////////////////////////////// probability of correct response
#>   pi[1,1] = inv_logit(l1_0);
#>   pi[1,2] = inv_logit(l1_0+l1_11);
#>   pi[2,1] = inv_logit(l2_0);
#>   pi[2,2] = inv_logit(l2_0+l2_11);
#>   pi[3,1] = inv_logit(l3_0);
#>   pi[3,2] = inv_logit(l3_0+l3_11);
#>   pi[4,1] = inv_logit(l4_0);
#>   pi[4,2] = inv_logit(l4_0+l4_11);
#> }
#> model {
#>   ////////////////////////////////// priors
#>   Vc ~ dirichlet(rep_vector(1, C));
#>   l1_0 ~ normal(0, 2);
#>   l1_11 ~ lognormal(0, 1);
#>   l2_0 ~ normal(0, 2);
#>   l2_11 ~ lognormal(0, 1);
#>   l3_0 ~ normal(0, 2);
#>   l3_11 ~ lognormal(0, 1);
#>   l4_0 ~ normal(0, 2);
#>   l4_11 ~ lognormal(0, 1);
#> 
#>   ////////////////////////////////// likelihood
#>   for (r in 1:R) {
#>     row_vector[C] ps;
#>     for (c in 1:C) {
#>       array[num[r]] real log_items;
#>       for (m in 1:num[r]) {
#>         int i = ii[start[r] + m - 1];
#>         log_items[m] = y[start[r] + m - 1] * log(pi[i,c]) +
#>                        (1 - y[start[r] + m - 1]) * log(1 - pi[i,c]);
#>       }
#>       ps[c] = log_Vc[c] + sum(log_items);
#>     }
#>     target += log_sum_exp(ps);
#>   }
#> }

stan_data(new_model, data = mdm_data, identifier = "respondent") |>
  str()
#> List of 9
#>  $ I    : int 4
#>  $ R    : int 142
#>  $ N    : int 568
#>  $ C    : int 2
#>  $ ii   : num [1:568] 1 2 3 4 1 2 3 4 1 2 ...
#>  $ rr   : num [1:568] 1 1 1 1 2 2 2 2 3 3 ...
#>  $ y    : int [1:568] 1 1 1 1 1 1 1 1 1 1 ...
#>  $ start: int [1:142] 1 5 9 13 17 21 25 29 33 37 ...
#>  $ num  : int [1:142] 4 4 4 4 4 4 4 4 4 4 ...

Contributions and Code of Conduct

Contributions are welcome. To ensure a smooth process, please review the Contributing Guide. Please note that the dcmstan project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

Metadata

Version

0.1.0

License

Unknown

Platforms (78)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows