Bürkner 2021 - IRT Model Classes 1PL 2PL and Extensions

Summary

The Rasch (1PL), 2PL and 3PL models are the same logistic model with progressively more item-level parameters: easiness only; plus discrimination ; plus guessing . Discrimination makes the predictor non-linear (a product of parameters), which brms handles through non-linear formulas.

Overview

Notation: person with ability ; item with easiness (brms convention; classical difficulty is ), discrimination and guessing . The distributional parameter is .

Main Content

Rasch / 1PL

. Higher raises success probability on every item; higher raises it for every person. Equal discriminations weight all items equally, so persons with the same total score get the same estimate.

2PL

. The argument is a product of parameters, so no longer a linear predictor (a generalized non-linear mixed model).

3PL

with a link inverse such as the logistic; is the probability of a correct answer from guessing (e.g. 0.25 for four options). A 4PL adds an upper lapse bound.

Scale non-identifiability of the 2PL

The 2PL likelihood is unchanged under , , . Hence the person standard deviation must be fixed (usually ), otherwise the scale of the person distribution is absorbed by the discriminations. A sign switch of with sign switch of is also a symmetry; impose by modelling .

Proof. ; the likelihood depends only on this product. (Checked numerically below.)

Examples

Likelihood invariance in a simulated 2PL

Setup. 200 persons, 20 items, , , ; responses simulated from the 2PL. Solution. Log-likelihood at the truth is ; rescaling with (, , ) gives exactly the same value. Interpretation. The data cannot distinguish scale; choose (or an informative prior). A 3PL with gives at ability .

import numpy as np
rng = np.random.default_rng(0)
P, I = 200, 20
theta = rng.normal(0, 1, P); xi = rng.normal(0, 1, I); alpha = np.exp(rng.normal(0.2, 0.2, I))
y = rng.binomial(1, 1/(1+np.exp(-alpha[None, :]*(theta[:, None]+xi[None, :]))))
def ll(theta, xi, alpha):
    q = 1/(1+np.exp(-alpha[None, :]*(theta[:, None]+xi[None, :])))
    return (y*np.log(q)+(1-y)*np.log(1-q)).sum()
print(ll(theta, xi, alpha), ll(2*theta, 2*xi, alpha/2))   # identical

PyMC-style 2PL sketch (untested; the E116 model is of this form with marginalisation over ):

with pm.Model():
    sd_xi = pm.HalfNormal("sd_xi", 3)
    xi = pm.Normal("xi", 0, sd_xi, shape=I)               # item easiness
    log_alpha = pm.Normal("log_alpha", 0, 1, shape=I)     # discrimination > 0
    theta = pm.Normal("theta", 0, 1, shape=P)             # sd fixed to 1: identification
    eta = pm.math.exp(log_alpha[item]) * (theta[person] + xi[item])
    pm.Bernoulli("y", logit_p=eta, observed=y)

Connections

See Also

Bürkner 2021 - Priors Hierarchical Pooling and Identification · Bürkner 2021 - Worked Examples Binary Models VerbAgg