Notes Relative to R Packages¶
Several R packages implement overlapping careless-responding indices. IER aims
to provide a NumPy-first Python API with typed orchestration via screen() and
composite().
Related R packages¶
| Concept | Common R reference | IER function |
|---|---|---|
| Intra-individual response variability | careless::irv |
irv() |
| Longest identical string | careless::longstring |
longstring_scores() / registry "longstring" |
| Psychometric synonyms / antonyms | careless::psychsyn / psychant |
psychsyn() / psychant() |
| Mahalanobis distance | careless::mahad |
mahad() |
| Even–odd consistency | careless::evenodd |
evenodd(method="halves") (equals -careless::evenodd) |
| Person-fit / Guttman errors | PerFit / custom | guttman(), lz() |
| Polytomous Guttman errors | PerFit::Gpoly / Gnormed.poly |
gpoly(normalize=False) / gpoly() |
| Polytomous U3 | PerFit::U3poly |
u3poly() (not u3_poly()) |
| Transposed scalability | PerFit::Ht |
ht() |
| Transition entropy | custom / Meade & Craig style | markov() |
| Carelessness onset | changepoint literature | onset() |
| Lagged autocorrelation | responsePatterns::rp.acors |
autocorrelation() |
Exact function names, defaults, and NA handling differ across implementations. Do not expect bit-identical scores without aligning:
- missing-data policy (
na_rm) - correlation critical values (
psychsyn_critval) - psychometric synonym/antonym item correlations:
careless::psychsynuses pairwise-complete correlations, matched byitem_correlations="pairwise"(IndexOptions.psychsyn_item_correlations). IER's default"complete"mode treats an item with any missing response as undefined. Pairwise mode needs three shared respondents per item pair where R accepts two, and scores respondents with at least two answered pairs where careless requires three. A respondent whose answered pairs have zero within-pair variance scores 0.0 in IER, while careless returnsNAor, withresample_na, reshuffles the pair order. IER acceptsresample_naandrandom_seedfor compatibility, but they have no effect on scores - Mahalanobis flagging method (
chi2vsiqrvszscore) - whether scores are normalized (e.g., Guttman proportions)
- Guttman item order: IER orders items easiest first (descending item mean,
ties by column) and counts pairs where the harder item scores higher, the
error direction of PerFit's
G. IER 1.12 and earlier counted the reverse (Guttman-consistent) pairs, so guttman scores from those releases differ - random seeds for resampling methods (
individual_reliability) - even-odd orientation and algorithm:
evenodd(method="halves")reproducescareless::evenoddwith the sign flipped, so higher IER scores mean more consistent responding, and straight-lined profiles areNaNin both. The defaultmethod="item_pairs"is IER-specific and correlates items within each factor rather than half-scale means across factors - IRV divisor (
ddof); IER matches NumPy / typical Rsdon a vector with population vs sample conventions checked explicitly in tests - item-step person fit:
gpoly(),u3poly(), andht()follow PerFit's definitions ofGpoly,Gnormed.poly,U3poly, andHt, including step popularity ties broken by item and then step (rank(ties.method = "first")). IER infers the category range from the observed responses unlessscale_minorncatis given, while PerFit'sNcatassumes categories coded from 0. Normalizedgpolyandu3polyreturnNaNfor perfect response vectors, where every step is failed or every step is passed, while PerFit'sGnormed.polyandU3poly, andGnormedfor dichotomous items, return 0. Incomplete respondents areNaNfor normalizedgpoly,u3poly, andht(rawgpolycounts observed step pairs). PerFit's defaultNA.method = "Pairwise"does not impute: it scores incomplete respondents from their observed items, and only itsHotdeck,NPModel, andPModelmethods impute missing responses. U3 weights clip steps passed by every or no respondent to half a response from the boundary. Theu3_poly()index is the proportion of extreme responses, not PerFit's U3 - autocorrelation lag range:
autocorrelation()defaults tomax_lag=10, whererp.acorsuses up toJ - 3lags; passmax_lag=Nonefor that range. IER lags start atmin_lag(default 1) and each lag needs three response pairs. As inrp.acors, a lag scores 1 when either lagged window has zero variance, so identical responses score 1 at every usable lag and a straight-liner whose first or last response differs does too. Both return the smallest lag among tied maxima; IER counts correlations within floating-point rounding as tied
Golden fixtures in this repo¶
tests/test_golden_parity.py locks hand-verified / regression values for:
irv, longstring, longstring_pattern, mahad (iqr), psychsyn,
evenodd (method="item_pairs"), guttman, markov, person_total,
midpoint, lz, and onset. tests/test_evenodd_halves.py checks
evenodd(method="halves") against a respondent-by-respondent port of careless's
R/evenodd.R, including missing halves, odd-sized and single-item factors.
gpoly(), u3poly(), and ht() have no R-generated fixtures. Their values
follow PerFit's published definitions and are validated in
tests/test_person_fit.py against independent brute-force oracles written from
the original papers: explicit enumeration of step pairs, maxima and U3 weight
extremes over every nested response pattern for small scales, and the naive
O(N^2 J) covariance form of Ht in exact integers. Dichotomous gpoly() also
reproduces guttman() counts divided by r * (J - r).
JSON copies under tests/fixtures/parity/ power a harness that loads the same
matrices and expected vectors. Treat JSON as the portable contract if you want
to regenerate expectations from R and drop in a replacement file.
Regenerating fixtures from R¶
- Export the fixture
matrixfrom JSON to CSV. - Score the matching R function with aligned options (NA policy, critval, …).
- Replace the
expectedvectors (usenullfor NaN). - Run
pytest tests/test_golden_parity.py -q.
Example sketch for IRV / longstring:
library(jsonlite)
library(careless)
fix <- fromJSON("tests/fixtures/parity/irv_longstring.json")
x <- as.matrix(fix$matrix)
Suggested validation workflow¶
If you need parity with an existing R pipeline:
- Export the same respondent × item matrix from both environments.
- Compare one index at a time on complete cases.
- Match options explicitly (critical values, normalization, seeds).
- Treat residual differences as implementation notes in your methods section.
What IER adds for Python users¶
- Unified
screen()/composite()registry with soft per-index errors - Shared
IndexOptionsconfig object (sole config surface for orchestration APIs) - Strict typing (
py.typed) and CI across Python 3.11–3.14 - Dependency-free statistical routines with an optional matplotlib plotting extra
- CLI:
ier screen data.csv/ier composite data.csvwith JSON/CSV export - Explicit documentation that composite logistic scores are uncalibrated
- Response-time helpers kept out of band (timing matrices ≠ item responses)
- Architecture note covering registry, flagging, and NA policy
- Synthetic detection-rate benchmark (
benchmarks/bench_detection.py)