Skip to contents

PP 1.0.0

PP 1.0.0 rebuilds the numerical core. Every estimate is now checked against independent reference implementations. For ordinary data (complete responses, no extreme scores) the MLE, WLE, MAP and EAP estimates of 0.6.4-1 are reproduced (differences below 0.001, within the convergence criterion exac; robust estimates differ by about 0.005). Results change in the places listed below: standard errors of MAP and robust estimates, the jackknife, plausible values, person fit, and edge cases such as missing responses, extreme scores and the 3PL. Function and argument names are unchanged unless stated.

Changed results

  • Jackknife (JKpp()): the standard error now follows the textbook formula for pseudovalues; it is larger than before (by a factor of about L − 1, L = number of items) and comparable to the MLE/WLE standard error. The jackknife runs over the answered items only (before: all items), leave-one-out samples without a finite estimate are counted in the new column excluded with a warning, and the EAP jackknife works for mixed tests.
  • AMT jackknife (cmeth = "AMT"): now the AMT-robustified jackknife of Wainer & Wright (1980): Andrews’ sine estimator (c = 2.1, MAD scale), applied to the pseudovalues of the right and of the wrong answers separately and averaged with the group sizes as weights.
  • MAP standard errors now include the prior.
  • Robust estimates: the standard error is the sandwich form with the Huber weights, and the estimate solves its weighted estimating equation to the accuracy exac (before up to 3e-3 off).
  • WLE/MLE for the 3PL: the estimator is now a safeguarded Newton method per person. Persons for whom the iteration oscillated without converging are now estimated or flagged by status.
  • Plausible values (PV()) are drawn from the posterior on a grid (approx = FALSE) or from a normal distribution with its mean and SD (approx = TRUE, default). Both use the prior of each person and work with missing responses. The Metropolis-Hastings sampler is gone, and its arguments thinning, burnin and mult are ignored with a warning.
  • EAP estimates are computed on an adaptive grid with log-likelihoods, which also works for long tests (products of probabilities underflowed there).
  • Person fit (Pfit()): lz* uses the answered items only, so it works with missing responses; infit and outfit of the PCM take the number of categories from the item parameters and respect the slopes of the GPCM; the jackknife SE of lz uses person-specific priors. Results are no longer rounded (p values of 0.0004 were shown as 0).
  • Scalar mu, sigma2 or item parameters are recycled to the persons or items.
  • The key for detecting duplicated response patterns could, in rare cases, treat different patterns as equal. The option killdupli is gone (see Deprecated).
  • Numerically stable item probabilities (no overflow in the 4PL, log-sum-exp in the GPCM), also in sim_4pl() and sim_gpcm().

Breaking changes

  • PV() needs an estimate with a prior, i.e. type = "eap" or "map"; it stops for MLE, WLE and robust estimates. These have no prior any more: mu and sigma2 given there are ignored with a warning and stored as NA.
  • Persons whose estimating equation has no root inside range (new argument, default c(-6, 6)) get the bound with status "boundary" and a warning (before: NaN or drifting values). Persons without any response get NA (before: +Inf); for EAP the prior mean and SD.
  • The results are numbered by person in the order of the response matrix; row names of respm are not carried over (use a person variable in PPass() for ids).
  • PPass() on eRm objects: the method PPass.Rm is replaced by PPass.eRm, and the result of PPass() is a data.frame of class ppass with the new column status. For type = "eap" and "robust" it contains the estimates only (with a message).
  • sim_4pl() and sim_gpcm() draw differently, so simulated data are not identical to 0.6.4-1 for the same seed.
  • Removed: lzstar_mixed(), Pfit_lzstarmix() and print_personfit_summary() (new in 0.6.4-1). Pfit() now gives lz and lz* for all models (lz* after Sinharay, 2016, with the correction of the estimation type), summary() of its result replaces the printed summary. Pfit() takes the item parameters from the estimation object.
  • The element $ipar of estimation objects (the processed input in the 0.6.4 layout) is no longer part of the result; the estimates are in $estimates.
  • JKpp(maxsteps, exac) default to the values of the estimation object (before 500 and 0.001).
  • Pfit(pp, fitindices, SE): the argument respm is removed, the responses come from the estimation object. Use Pfit(res) instead of Pfit(respm = X, pp = res). The estimation objects of 0.6.4-1 did not contain the rows of persons with an extreme score (MLE) and of duplicated patterns, so the responses had to be passed again; the new objects have one row per person.

New features

  • Every result has $estimates, a data.frame with estimate, SE, nsteps and status ("ok", "extreme", "boundary", "no_response", "not_converged") per person; coef() and as.data.frame() methods. JKpp() returns $estimates with L, excluded and status.
  • New arguments range and verbose in PP_4pl(), PP_gpcm() and PPall(). Defaults are unified: maxsteps = 100, exac = 0.001.
  • Pfit() works for all models (1PL–4PL, PCM, GPCM and mixed tests), for MLE, WLE and MAP, with missing responses. Jackknife SEs for all four statistics (new columns in_se, ou_se), print() and summary().
  • PPass():
    • no longer needs mod and model2est: the model (1PL to 4PL, PCM, GPCM or a mixed test) follows from the item parameters, as in PP_4pl(); both are ignored with a warning. Before, mod only switched between PP_4pl(), PP_gpcm() and PPall(), and mod = "MIXED" did not work.
    • works with a matrix; items can be given by name; the other columns (e.g. an id) are kept as person variables.
    • takes every eRm model: RM, LLTM, RSM, PCM, LRSM and LPCM, also with several time points and groups, including group contrasts, for which eRm gives no person parameters. Its maximum likelihood estimates equal eRm::person.parameter(). eRm is not needed at run time.
    • print() and summary() give an overview with the persons flagged by the person fit; JKpp() and PV() work directly on the result.
  • plot() for the results of PPass(), PP_4pl(), PP_gpcm() and PPall() (help page ?"pp-plots"), drawn with the new dependency tinyplot:
    • which = "fit": person fit map, the fit statistic against the estimate with the flagged persons labelled;
    • which = "precision": the standard error of each person and of the whole test, 1/sqrt(I(theta)) from the known item parameters, below the distribution of the estimates and with the location of every item;
    • which = "profile": observed against expected scores of the answered items of single persons, with the unexpected answers labelled.
  • sim_mixed() simulates tests of 4PL and GPCM items.
  • PPall(): slopes, lowerA and upperA are optional; PP_4pl() with lowerA but without slopes fits the 3PL with slopes 1.
  • Input checks with clear messages for all arguments.
  • No startup message, no cat() output and no warning for the default prior.

Deprecated

  • The options of ctrl in PP_4pl(), PP_gpcm() and PPall() are ignored with a warning: killdupli (estimate duplicated response patterns once) and skipcheck (skip the checks of the responses) saved time with the old estimation routine, which iterated all persons together. Every person is now estimated separately, and the checks always run. JKpp(ctrl) had no effect already in 0.6.4-1 and is ignored with a warning, too.
  • PPall(model2est) is ignored with a warning: the model of each item follows from thres (one threshold: 4PL item, several: GPCM item). A dichotomous item declared as "GPCM" was the same as a 4PL item with asymptotes 0 and 1. findmodel() shows the model of each item.
  • $resPP (estimation objects) and $resjk (jackknife) are kept as aliases of the 0.6.4 layout; use $estimates.

Performance

The C++ core estimates every person separately with its own convergence check (before: all persons iterated until the slowest converged). Median times on 5000 persons × 40 items: 1PL–3PL estimates 0.02 s (before 0.3–2.9 s), EAP 0.03 s (0.8 s); GPCM with 2000 × 20: 0.01 s (0.2–1.3 s); JKpp() on 500 × 40: 0.05 s (142 s); PV() 150 times and sim_gpcm() 400 times faster.

Documentation

  • New vignettes: “Getting started with PP”, “Person fit with PP” and “Person assessment with PPass, also for eRm models”.
  • Examples are part of the help pages.

Maintenance

  • Manuel Reif is the maintainer again. The repository moved to https://github.com/manuelreif/PP.
  • PP needs R >= 4.0 (before 3.0) and imports tinyplot for the new plots.

PP 0.6.4-1

CRAN release: 2026-04-21

  • Person fit for mixed tests: lzstar_mixed(), Pfit_lzstarmix(), print_personfit_summary().
  • Jan Steinfeld became the maintainer.