Package {guess}


Title: Adjust Estimates of Learning for Guessing
Version: 0.7.0
Description: Provides tools to adjust estimates of learning for guessing-related bias in educational and survey research. Implements standard guessing correction methods and latent class models that leverage informative pre-post test transitions to account for guessing behavior. The package helps researchers obtain more accurate estimates of actual learning when respondents may guess on closed-ended knowledge items. For theoretical background and empirical validation, see Cor and Sood (2016) https://gsood.com/research/papers/guess.pdf.
URL: https://github.com/finite-sample/guess, https://finite-sample.github.io/guess/
BugReports: https://github.com/finite-sample/guess/issues
Depends: R (≥ 4.0.0)
Imports: Rsolnp, stats, checkmate
License: MIT + file LICENSE
VignetteBuilder: knitr
Suggests: knitr (≥ 1.11), rmarkdown, testthat (≥ 3.0.0), lintr, covr, dplyr, tibble
Encoding: UTF-8
Language: en-US
Config/testthat/edition: 3
Config/roxygen2/version: 8.0.0
NeedsCompilation: no
Packaged: 2026-08-03 00:45:49 UTC; soodoku
Author: Gaurav Sood [aut, cre], Ken Cor [aut]
Maintainer: Gaurav Sood <gsood07@gmail.com>
Repository: CRAN
Date/Publication: 2026-08-03 02:20:02 UTC

guess adjust estimates of learning for guessing related bias.

Description

It implements the method discussed in https://gsood.com/research/papers/guess.pdf

Author(s)

Maintainer: Gaurav Sood gsood07@gmail.com

Authors:

See Also

Useful links:


Calculate expected values for goodness of fit test

Description

Calculate expected values for goodness of fit test

Usage

calculate_expected_values(gamma_i, params, total_obs, model_type = "nodk")

Arguments

gamma_i

item-specific gamma value

params

estimated parameters for the item

total_obs

total observations for the item

model_type

"nodk" or "dk" model

Value

vector of expected values


Model Criticism Tools

Description

Functions for evaluating model fit via held-out likelihood and perplexity. Two parallel sets of functions: - '*_items': Work on aggregated transition matrices, CV/evaluate over items - '*_individuals': Work on raw individual data, CV/evaluate over individuals Calculate cell probabilities from parameters

Usage

cell_probs(params)

Arguments

params

numeric vector of length 4 (nodk) or 8 (dk)

Value

numeric vector of cell probabilities


Class-conditional likelihood for single item

Description

Returns P(response | class, gamma) for each latent class.

Usage

class_conditional_item(pre, post, gamma)

Arguments

pre

numeric (0 or 1) pre-test response

post

numeric (0 or 1) post-test response

gamma

numeric guessing probability

Value

named numeric vector of length 3 (P for gg, gk, kk)


Extract coefficients from guess_fit

Description

Extract coefficients from guess_fit

Usage

## S3 method for class 'guess_fit'
coef(object, ...)

Arguments

object

guess_fit object

...

ignored

Value

parameter matrix


Count transitions between pre and post test responses

Description

Count transitions between pre and post test responses

Usage

count_transitions(pre_responses, pst_responses)

Arguments

pre_responses

character vector of pre-test responses

pst_responses

character vector of post-test responses

Value

named vector of transition counts


Cross-sectional learning estimate

Description

Estimates learning as the difference in logit scores between post and pre. This ignores the transition structure that the LCA model uses.

Usage

cross_sectional_learning(
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

na_as

classification of NA responses

missing_action

structural missingness handling

Value

numeric vector of learning scores (post - pre)

Examples

sim <- simulate_lca(n = 100, gk = 0.30, seed = 123, return_classes = TRUE)
learning_cs <- cross_sectional_learning(sim$pre, sim$post)
cor(learning_cs, sim$learned)

Cross-Sectional Learning Score

Description

Applies the logistic function to the difference in cross-sectional logit scores. The result is bounded in [0, 1], but is not a calibrated probability of learning and is not an IRT estimate.

Usage

cross_sectional_learning_score(
  pre_test,
  pst_test,
  scale = 1,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

scale

numeric scaling factor for the score difference (default 1)

na_as

classification of NA responses

missing_action

structural missingness handling

Value

numeric vector of learning scores in [0, 1]

Examples

sim <- simulate_lca(n = 100, gk = 0.30, seed = 123, return_classes = TRUE)
learning_score <- cross_sectional_learning_score(sim$pre, sim$post)
cor(learning_score, sim$learned)

K-fold cross-validation over individuals

Description

Splits individuals into k folds, fits on training, evaluates on held-out.

Usage

cv_individuals(
  pre_test,
  pst_test,
  k = 5L,
  priors = NULL,
  seed = NULL,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

k

integer number of folds

priors

optional numeric vector of starting parameters

seed

optional integer random seed

na_as

classification of NA responses

missing_action

structural missingness handling

Value

list with fold_results, mean_ll, total_ll, perplexity, se


K-fold cross-validation over items

Description

Splits items into k folds, fits on training items, evaluates on held-out items.

Usage

cv_items(transmatrix, k = 5L, priors = NULL, seed = NULL)

Arguments

transmatrix

numeric matrix from multi_transmat()

k

integer number of folds

priors

optional numeric vector of starting parameters

seed

optional integer random seed

Value

list with fold_results, mean_ll, total_ll, perplexity, se


Transform difficulty to gamma

Description

Convert a difficulty score to a guessing probability.

Usage

difficulty_to_gamma(difficulty, base_rate = 0.25)

Arguments

difficulty

numeric vector of difficulty parameters

base_rate

minimum guessing probability (1/K for K-choice items)

Value

numeric vector of gamma values


Cell probabilities for the model with Don't Know

Description

The multinomial cell probabilities implied by the latent class transition parameters, as in equation (2) of Cor and Sood. The nine latent transitions among guess (g), know (k) and don't know (d) are reduced to seven by the identifying assumption that people do not lose knowledge over the course of a short informative process: the know-to-guess and know-to-don't-know classes are identically zero and do not appear.

The seven remaining proportions sum to 1, and so do the nine cell probabilities returned here. Given those probabilities the parameters are recoverable in closed form – gamma / (1 - gamma) is x10 / x00 – with one over-identifying restriction left over, x1d / x0d = x10 / x00.

Usage

dk_cell_probs(gg, gk, gd, kk, dg, dk, dd, g1)

Arguments

gg

proportion guess -> guess

gk

proportion guess -> know

gd

proportion guess -> don't know

kk

proportion know -> know

dg

proportion don't know -> guess

dk

proportion don't know -> know

dd

proportion don't know -> don't know

g1

probability a guess is correct (gamma)

Value

numeric vector of length 9, ordered x00, x01, x0d, x10, x11, x1d, xd0, xd1, xdd


Constraints: Sum to 1

Description

Constraints that some params sum to 1. Used Internally. For data with DK. Functions for constraining lambdas to sum to 1 and to bound params between 0 and 1

Usage

eq1dk(x, g1 = NA, data)

Arguments

x

gg, gk, gd, kk, dg, dk, dd

g1

guess

data

transition matrix


Sum to 1 constraint (no DK)

Description

Constraints that some params sum to 1. Used Internally. For data without DK. Functions for constraining lambdas to sum to 1 and to bound params between 0 and 1

Usage

eqn1(x, g1 = NA, data)

Arguments

x

gg, gk, kk

g1

guess

data

transition matrix


Estimate a Cross-Sectional Logit Score

Description

Computes the logit of each person's proportion correct. This is a descriptive score, not a fitted item-response model.

Usage

estimate_logit_score(
  responses,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

responses

data.frame of binary responses (0/1)

na_as

classification of NA responses

missing_action

structural missingness handling

Details

Observed d/DK responses are scored as incorrect in this binary correctness baseline. They remain a distinct response category in the LCA functions.

Value

numeric vector of logit scores (length = n individuals)

Examples

sim <- simulate_lca(n = 100, seed = 123)
score_pre <- estimate_logit_score(sim$pre)
score_post <- estimate_logit_score(sim$post)

Extract parameter matrix from lca_result

Description

Extract parameter matrix from lca_result

Usage

extract_params(lca_result)

Arguments

lca_result

output from lca_cor/item_lca_fit or numeric vector

Value

matrix of parameters (rows = params, cols = items)


Goodness of fit statistics for transition matrix data

Description

Pearson chi-square goodness of fit between the observed transition counts and those the fitted model implies. Handles data with and without don't know responses automatically.

Degrees of freedom are the free cell probabilities less the parameters estimated from the same counts. The don't-know model leaves 1 degree of freedom. The model without don't know is saturated – 3 free parameters against 3 free cell probabilities – so no test is possible and both rows are 'NA'.

Usage

fit_model(
  pre_test,
  pst_test,
  g,
  est_param,
  force9 = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

fit_dk(
  pre_test,
  pst_test,
  g,
  est_param,
  force9 = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

fit_nodk(
  pre_test,
  pst_test,
  g,
  est_param,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

data.frame carrying pre_test items

pst_test

data.frame carrying pst_test items

g

estimates of gamma produced from lca_cor

est_param

estimated parameters produced from lca_cor

force9

Optional. Force 9-column format even if no DK responses. Default is FALSE.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes incomplete pairs and '"error"' rejects them.

Details

Unified Goodness of Fit Statistics

Value

matrix with two rows: top row carrying chi-square value, bottom row p-values

Examples

## Not run: 
# Fit model first
transmatrix <- multi_transmat(pre_test, pst_test)
res <- lca_cor(transmatrix)

# Calculate goodness of fit
fit_stats <- fit_model(
  pre_test, pst_test, res$params[nrow(res$params), ],
  res$params[-nrow(res$params), ]
)

## End(Not run)

Format transition matrix result with appropriate row and column names

Description

Format transition matrix result with appropriate row and column names

Usage

format_transition_matrix(transition_list, n_items, add_aggregate = FALSE)

Arguments

transition_list

list of transition vectors

n_items

number of items

add_aggregate

whether to add aggregate row

Value

formatted matrix


Transform gamma to difficulty

Description

Convert guessing probability to a difficulty score.

Usage

gamma_to_difficulty(gamma, base_rate = 0.25)

Arguments

gamma

numeric vector of guessing probabilities

base_rate

minimum guessing probability (1/K for K-choice items)

Value

numeric vector of difficulty values


Group Level Adjustment That Accounts for Propensity to Guess

Description

Adjusts observed 1s based on propensity to guess (based on observed 0s) and item level gamma. You can also put in your best estimate of hidden knowledge behind don't know responses.

Usage

group_adj(
  pre = NULL,
  pst = NULL,
  gamma = NULL,
  dk = 0.03,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre

pre data frame. Required. Each vector within the data frame should only take values 0, 1, and 'd'.

pst

pst data frame. Required. Each vector within the data frame should only take values 0, 1, and 'd'.

gamma

probability of getting the right answer without knowledge

dk

Numeric. Between 0 and 1. Hidden knowledge behind don't know responses. Default is .03.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes it and '"error"' rejects it.

Value

nested list of pre and post adjusted responses, and adjusted learning estimates

Examples

pre_test_var <- data.frame(pre = c(1, 0, 0, 1, "d", "d", 0, 1, NA))
pst_test_var <- data.frame(pst = c(1, NA, 1, "d", 1, 0, 1, 1, "d"))
gamma <- c(.25)
group_adj(pre_test_var, pst_test_var, gamma)

guess_lik

Description

Likelihood function for data without Don't Know. Used Internally.

Usage

guess_lik(x, g1 = x[4], data)

Arguments

x

gg, gk, kk

g1

guess

data

transition matrix


guessdk_lik

Description

Likelihood function for data with Don't Know. Used Internally.

Usage

guessdk_lik(x, g1 = x[8], data)

Arguments

x

gg, gk, gd, kk, dg, dk, dd

g1

guess

data

transition matrix


Calculate per-individual log-likelihood

Description

Calculate per-individual log-likelihood

Usage

individual_likelihood_details(
  lca_result,
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

individual_log_likelihood(
  lca_result,
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

lca_result

output from lca_cor() or item_lca_fit()

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

na_as

classification of NA responses

missing_action

structural missingness handling

Value

numeric vector of log-likelihoods (length = n individuals)


Interleave vectors

Description

Interleaves two vectors. Used internally.

Usage

interleave(a, b)

Arguments

a

first vector

b

second vector


Fit Independent Item-Wise LCA Models

Description

Creates one transition matrix per item and fits independent class proportions and guessing probabilities for every item.

Usage

item_lca_fit(
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error"),
  ...
)

Arguments

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

na_as

classification of NA responses

missing_action

structural missingness handling

...

passed to lca_cor()

Value

output from lca_cor()


Person Level Adjustment

Description

Adjusts observed 1s based on item level parameters of the LCA model. Currently only takes data with Don't Know. And treats don't know responses as true confessions on ignorance. By default, NAs are treated as acknowledgments of ignorance.

Usage

lca_adj(
  pre = NULL,
  pst = NULL,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre

pre data frame

pst

pst data frame

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes it and '"error"' rejects it.

Value

list of pre and post adjusted responses

Examples

pre_test_var <- data.frame(pre = c(1, 0, 0, 1, "d", "d", 0, 1, NA))
pst_test_var <- data.frame(pst = c(1, NA, 1, "d", 1, 0, 1, 1, "d"))
lca_adj(pre_test_var, pst_test_var)

Calculate item level and aggregate learning

Description

guesstimate

Usage

lca_cor(
  transmatrix = NULL,
  nodk_priors = c(0.3, 0.1, 0.1, 0.25),
  dk_priors = c(0.3, 0.15, 0.1, 0.2, 0.05, 0.1, 0.1, 0.25)
)

Arguments

transmatrix

transition matrix returned from multi_transmat

nodk_priors

Optional. Vector of length 4. Priors for the parameters for model that fits data without Don't Knows

dk_priors

Optional. Vector of length 8. Priors for the parameters for model that fits data with Don't Knows

Value

list with two items: parameter estimates and estimates of learning

Examples

# Without DK
pre_test <- data.frame(item1 = c(1, 0, 0, 1, 0), item2 = c(1, NA, 0, 1, 0))
pst_test <- pre_test + cbind(c(0, 1, 1, 0, 0), c(0, 1, 0, 0, 1))
transmatrix <- multi_transmat(pre_test, pst_test)
res <- lca_cor(transmatrix)

Estimate LCA model with a bounded guessing-probability link

Description

Fits an LCA model where item difficulty is parameterized using an unbounded real-valued parameter instead of raw gamma (guessing probability). This is a reparameterized LCA, not an item-response model: it contains no person ability parameter.

Usage

lca_difficulty(
  transmatrix = NULL,
  base_rate = 0.25,
  nodk_priors = c(0.35, 0.3, 0.35, 0),
  dk_priors = c(0.25, 0.15, 0.1, 0.2, 0.1, 0.1, 0.1, 0)
)

Arguments

transmatrix

Transition matrix returned from multi_transmat

base_rate

Numeric. Minimum guessing probability (random chance). Default 0.25 (1/4 for 4-choice items). This is the floor for gamma when difficulty -> +Inf.

nodk_priors

Optional. Vector of length 4. Starting values for (gg, gk, kk, difficulty). First 3 must sum to 1.

dk_priors

Optional. Vector of length 8. Starting values for DK model. First 7 must sum to 1.

Details

Difficulty-Parameterized LCA Estimation

The relationship between difficulty (d) and gamma is:

\gamma = base\_rate + (1 - base\_rate) \cdot logistic(-d)

Where logistic(x) = 1/(1+exp(-x)). This means:

Value

A guess_fit object with additional components:

params

Parameter matrix with "difficulty" row instead of "gamma"

gamma

Derived gamma values from difficulty (added for convenience)

learning

Learning estimates (gk or gk + kd)

Examples

# Simulate data with known difficulty
sim <- simulate_lca(n = 500, n_items = 3, difficulty = c(1, 0, -1), seed = 123)
transmatrix <- multi_transmat(sim$pre, sim$post)

# Fit with the difficulty-link parameterization
fit <- lca_difficulty(transmatrix)
fit$params["difficulty", ] # Should recover approximately c(1, 0, -1)
fit$gamma # Derived gamma values

Bootstrapped standard errors of effect size estimates

Description

Bootstrapped Standard Errors

Usage

lca_se(
  pre_test = NULL,
  pst_test = NULL,
  n_resamples = 100,
  seed = 31415,
  force9 = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

data.frame carrying pre_test items

pst_test

data.frame carrying pst_test items

n_resamples

number of resamples, default is 100

seed

random seed, default is 31415

force9

Optional. Force 9-column format even if no DK responses. Default is FALSE.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes incomplete pairs and '"error"' rejects them.

Value

list with:

se_params

standard errors of parameters by item

avg_effects

mean learning estimates

se_effects

standard error of learning by item

Examples

pre_test <- data.frame(pre_item1 = c(1, 0, 0, 1, 0), pre_item2 = c(1, NA, 0, 1, 0))
pst_test <- data.frame(
  pst_item1 = pre_test[, 1] + c(0, 1, 1, 0, 0),
  pst_item2 = pre_test[, 2] + c(0, 1, 0, 0, 1)
)
## Not run: 
lca_se(pre_test, pst_test, n_resamples = 10, seed = 31415)

## End(Not run)

Calculate log-likelihood for transition data

Description

Calculate log-likelihood for transition data

Usage

log_likelihood(params, data)

Arguments

params

numeric vector of length 4 (nodk) or 8 (dk)

data

numeric vector of transition counts

Value

scalar log-likelihood

Examples

params <- c(0.4, 0.3, 0.3, 0.25)
data <- c(x00 = 10, x01 = 5, x10 = 3, x11 = 12)
log_likelihood(params, data)

Create difficulty-parameterized likelihood function (no DK)

Description

Factory function that creates a likelihood function parameterized with an unbounded difficulty score instead of gamma. Used internally by lca_difficulty().

Usage

make_guess_lik_difficulty(base_rate = 0.25)

Arguments

base_rate

minimum guessing probability (1/K for K-choice items)

Value

A function that takes x (parameters) and data (transition matrix)


Create difficulty-parameterized likelihood function (DK)

Description

Factory function that creates a likelihood function parameterized with an unbounded difficulty score instead of gamma. Used internally by lca_difficulty().

Usage

make_guessdk_lik_difficulty(base_rate = 0.25)

Arguments

base_rate

minimum guessing probability (1/K for K-choice items)

Value

A function that takes x (parameters) and data (transition matrix)


Creates a transition matrix for each item.

Description

Needs an 'interleaved' dataframe (see interleave function). Pre-test item should be followed by corresponding post-item item etc. Don't knows may be coded as d/DK or, by default, NA. Function handles items without don't know responses. The function is used internally. It calls transmat.

Usage

multi_transmat(
  pre_test = NULL,
  pst_test = NULL,
  subgroup = NULL,
  force9 = FALSE,
  agg = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

Required. data.frame carrying responses to pre-test questions.

pst_test

Required. data.frame carrying responses to post-test questions.

subgroup

a Boolean vector identifying the subset. Default is NULL.

force9

Optional. There are cases where DK data doesn't have DK. But we need the entire matrix. By default it is FALSE.

agg

Optional. Boolean. Whether or not to add a row of aggregate transitions at the end of the matrix. Default is FALSE.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes incomplete pairs and '"error"' rejects them.

Details

multi_transmat: transition matrix of all the items

Value

matrix with rows = total number of items + 1 (last row contains aggregate distribution across items) number of columns = 4 when no don't know, and 9 when there is a don't know option

Examples

pre_test <- data.frame(pre_item1 = c(1, 0, 0, 1, 0), pre_item2 = c(1, NA, 0, 1, 0))
pst_test <- data.frame(
  pst_item1 = pre_test[, 1] + c(0, 1, 1, 0, 0),
  pst_item2 = pre_test[, 2] + c(0, 1, 0, 0, 1)
)
multi_transmat(pre_test, pst_test)

Multinomial negative log-likelihood

Description

Multinomial negative log-likelihood

Usage

multinomial_nll(data, probs)

Arguments

data

observed cell counts

probs

model-implied cell probabilities

Value

scalar negative log-likelihood


Create a guess_cv object

Description

Create a guess_cv object

Usage

new_guess_cv(
  fold_results,
  mean_ll,
  total_ll,
  perplexity,
  se,
  cv_type,
  k,
  call = NULL
)

Arguments

fold_results

data.frame of per-fold results

mean_ll

mean log-likelihood

total_ll

total log-likelihood

perplexity

perplexity

se

standard error of perplexity across folds

cv_type

"items" or "individuals"

k

number of folds

call

original function call

Value

object of class "guess_cv"


S3 Methods for guess Objects

Description

Print, summary, coef, vcov, and confint methods for guess model fits and cross-validation results. Create a guess_fit object

Usage

new_guess_fit(params, learning, n_items, n_obs, model_type, call = NULL)

Arguments

params

parameter matrix (rows = parameters, cols = items)

learning

learning estimates vector

n_items

number of items

n_obs

total observations

model_type

"nodk" or "dk"

call

original function call

Value

object of class "guess_fit"


Cell probabilities for the model without Don't Know

Description

The multinomial cell probabilities implied by the latent class transition parameters. This is the single definition of the model; every likelihood, expected-count and goodness-of-fit routine calls it rather than restating the algebra.

Latent classes are named pre-state then post-state over guess (g) and know (k), so 'gk' is guess at the pretest and know at the posttest. Knowledge is assumed not to be lost over the process, so the know-to-guess class is identically zero and does not appear.

Usage

nodk_cell_probs(gg, gk, kk, g1)

Arguments

gg

proportion guess -> guess

gk

proportion guess -> know

kk

proportion know -> know

g1

probability a guess is correct (gamma)

Value

numeric vector of length 4, ordered x00, x01, x10, x11


Normalize NA Responses

Description

Classifies NAs as observed don't know responses by default. If NAs represent structural missingness, they can instead be omitted or rejected.

Usage

nona(
  vec = NULL,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

vec

Required. Character or numeric vector.

na_as

Classification of NA responses: '"dk"' (the default) or '"missing"'.

missing_action

How to handle structural missingness: '"omit"' or '"error"'.

Value

Character vector.

Examples

x <- c(NA, 1, 0)
nona(x)
x <- c(NA, "dk", 0)
nona(x)

Normalize structural missingness handling

Description

Normalize structural missingness handling

Usage

normalize_missing_action(missing_action)

Arguments

missing_action

how structural missingness should be handled

Value

one of "omit" or "error"


Normalize how NA responses are classified

Description

Normalize how NA responses are classified

Usage

normalize_na_as(na_as)

Arguments

na_as

whether NA represents an observed don't know response or structural missingness

Value

one of "dk" or "missing"


Normalize raw item responses

Description

Normalize raw item responses

Usage

normalize_responses(
  x,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

x

response vector

na_as

classification of NA responses

missing_action

structural missingness handling

Value

character vector containing "0", "1", "d", or NA


Calculate perplexity from individual-level data

Description

Calculate perplexity from individual-level data

Usage

perplexity_individuals(
  lca_result,
  pre_test,
  pst_test,
  per_individual = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

lca_result

output from lca_cor() or item_lca_fit()

pre_test

data.frame of pre-test responses

pst_test

data.frame of post-test responses

per_individual

logical; return per-individual perplexity?

na_as

classification of NA responses

missing_action

structural missingness handling

Value

numeric scalar or vector


Calculate perplexity from aggregated item data

Description

Lower perplexity indicates better model fit.

Usage

perplexity_items(lca_result, transmatrix, item = NULL)

Arguments

lca_result

output from lca_cor() or numeric parameter vector

transmatrix

numeric matrix of transition counts (items x cells)

item

optional integer; specific item index (NULL = aggregate)

Value

numeric scalar perplexity

Examples

## Not run: 
transmatrix <- multi_transmat(pre_test, pst_test)
res <- lca_cor(transmatrix)
perplexity_items(res, transmatrix)

## End(Not run)

Person/item EM expectation step

Description

Person/item EM expectation step

Usage

person_item_expectation(pre, post, complete, class_priors, gamma)

Arguments

pre

numeric pre-test matrix

post

numeric post-test matrix

complete

logical matrix of complete response pairs

class_priors

shared class proportions

gamma

item-specific guessing probabilities

Value

posterior probabilities and observed-data log-likelihood


Fit a Joint Person-Level Latent Class Model

Description

Fits one latent transition class per person across repeated items. Class proportions are shared across items, while guessing probabilities are item-specific. Parameters are estimated jointly by expectation-maximization.

Usage

person_item_lca_fit(
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error"),
  item_fit = NULL,
  max_iter = 1000L,
  tol = 1e-08
)

Arguments

pre_test

data frame of pre-test responses

pst_test

data frame of post-test responses

na_as

classification of NA responses

missing_action

structural missingness handling

item_fit

optional item-wise fit used to initialize the EM algorithm

max_iter

maximum EM iterations

tol

convergence tolerance

Details

This is distinct from item_lca_fit, which fits independent class proportions for each item.

Value

An object of class guess_person_fit containing shared class proportions, item-specific guessing probabilities, person-level posterior probabilities, log-likelihood, and convergence information.

Examples

sim <- simulate_lca(n = 500, n_items = 4, seed = 123)
fit <- person_item_lca_fit(sim$pre, sim$post)
fit$class_priors
head(fit$posterior)

Person/item EM maximization step

Description

Person/item EM maximization step

Usage

person_item_maximization(pre, post, complete, expected, gamma, epsilon)

Arguments

pre

numeric pre-test matrix

post

numeric post-test matrix

complete

logical matrix of complete response pairs

expected

output from person_item_expectation

gamma

current item guessing probabilities

epsilon

boundary used to keep probabilities in the open interval

Value

updated class proportions and guessing probabilities


Person/item response probabilities

Description

Person/item response probabilities

Usage

person_item_response_probs(gamma)

Arguments

gamma

item guessing probability

Value

matrix with response pairs in rows and latent classes in columns


Compute posterior class probabilities

Description

Extracts P(class | response vector) for each individual from an explicitly fitted person/item model.

Usage

posterior_class_probs(object)

Arguments

object

output from person_item_lca_fit()

Value

data.frame with columns P_gg, P_gk, P_kk (rows = individuals)

Examples

sim <- simulate_lca(n = 100, gk = 0.30, seed = 123, return_classes = TRUE)
fit <- person_item_lca_fit(sim$pre, sim$post)
posteriors <- posterior_class_probs(fit)
head(posteriors)

Compute posterior probability of learning

Description

Returns P(gk | data) for each individual, representing the probability that the individual truly learned (vs. guessing or already knowing).

Usage

posterior_learned(object)

Arguments

object

output from person_item_lca_fit()

Value

numeric vector of P(learned | data) for each individual

Examples

sim <- simulate_lca(n = 100, gk = 0.30, seed = 123, return_classes = TRUE)
fit <- person_item_lca_fit(sim$pre, sim$post)
p_learned <- posterior_learned(fit)
cor(p_learned, sim$learned)

Normalize paired response data frames

Description

Normalize paired response data frames

Usage

prepare_response_data(
  pre_test,
  pst_test,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

pre-test response data frame

pst_test

post-test response data frame

na_as

classification of NA responses

missing_action

structural missingness handling

Value

list containing normalized pre-test and post-test data


Print method for guess_cv

Description

Print method for guess_cv

Usage

## S3 method for class 'guess_cv'
print(x, ...)

Arguments

x

guess_cv object

...

ignored

Value

invisible(x)


Print method for guess_fit

Description

Print method for guess_fit

Usage

## S3 method for class 'guess_fit'
print(x, ...)

Arguments

x

guess_fit object

...

ignored

Value

invisible(x)


Map pre/post response pairs to cell indices

Description

Map pre/post response pairs to cell indices

Usage

response_to_cell(
  pre,
  post,
  has_dk = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre

character vector of pre-test responses ("0", "1", or "d")

post

character vector of post-test responses ("0", "1", or "d")

has_dk

logical; whether model includes don't know

na_as

classification of NA responses

missing_action

structural missingness handling

Value

integer vector of cell indices


Simulation Functions for LCA Models

Description

Functions to generate simulated pre/post test data from known LCA parameters for validation and parameter recovery studies. Simulate Pre-Post Test Data (No DK Model)

Usage

simulate_lca(
  n,
  n_items = 1,
  gg = 0.35,
  gk = 0.3,
  kk = 0.35,
  gamma = 0.25,
  difficulty = NULL,
  base_rate = 0.25,
  seed = NULL,
  return_classes = FALSE
)

Arguments

n

Integer. Number of individuals to simulate.

n_items

Integer. Number of test items. Default 1.

gg

Numeric. Proportion in guess->guess state (stable ignorance). Default 0.35.

gk

Numeric. Proportion in guess->know state (LEARNED). Default 0.30.

kk

Numeric. Proportion in know->know state (stable knowledge). Default 0.35.

gamma

Numeric. Probability of guessing correctly. Can be scalar (same for all items) or vector of length n_items. Default 0.25.

difficulty

Numeric vector. Optional difficulty-link scores. If provided, gamma is computed as base_rate + (1 - base_rate) * plogis(-difficulty). Higher difficulty = harder item (lower gamma). Ignored if NULL.

base_rate

Numeric. Minimum guessing probability (random chance). Used when difficulty is specified. Default 0.25 (1/4 for 4-choice items).

seed

Optional integer. Random seed for reproducibility.

return_classes

Logical. If TRUE, also return true latent class assignments. Default FALSE for backward compatibility.

Details

Generates simulated pre/post test data from a latent class model with known parameters. Useful for parameter recovery validation studies.

The model simulates three latent classes: - **gg (guess->guess)**: Don't know at both times. Responses are random guesses. - **gk (guess->know)**: Learned between tests. Random guess pre, correct post. - **kk (know->know)**: Know at both times. Correct responses at both times.

Parameters must satisfy: gg + gk + kk = 1 (constraint enforced automatically).

When difficulty is specified, gamma values are derived using a logistic transformation: gamma_i = base_rate + (1 - base_rate) * plogis(-difficulty_i). This means: - difficulty = 0: gamma = base_rate + 0.5 * (1 - base_rate) (middle) - difficulty -> +Inf: gamma -> base_rate (hard item, random guessing) - difficulty -> -Inf: gamma -> 1 (easy item, always correct)

Value

List with components:

pre

Data frame of pre-test responses (0/1 for each item)

post

Data frame of post-test responses (0/1 for each item)

true_class

(If return_classes=TRUE) Factor with levels "gg", "gk", "kk"

learned

(If return_classes=TRUE) Logical vector: TRUE if individual is in gk class

Examples

# Simulate data with 30% learning
sim <- simulate_lca(n = 500, gg = 0.35, gk = 0.30, kk = 0.35, gamma = 0.25, seed = 123)
fit <- item_lca_fit(sim$pre, sim$post)
fit$params["gk", ] # Should be close to 0.30

# Multi-item simulation
sim_multi <- simulate_lca(n = 500, n_items = 3, seed = 456)

# Item-specific gamma (vector)
sim_vec <- simulate_lca(n = 500, n_items = 3, gamma = c(0.2, 0.25, 0.3), seed = 789)

# Difficulty-link scores
sim_irt <- simulate_lca(n = 500, n_items = 3, difficulty = c(1, 0, -1), seed = 101)

# Return true class assignments for validation
sim_classes <- simulate_lca(n = 500, gk = 0.30, seed = 123, return_classes = TRUE)
table(sim_classes$true_class)
mean(sim_classes$learned) # Should be close to 0.30

Simulate Pre-Post Test Data (DK Model)

Description

Generates simulated pre/post test data from a latent class model with Don't Know responses.

Usage

simulate_lca_dk(
  n,
  n_items = 1,
  gg = 0.25,
  gk = 0.15,
  gd = 0.1,
  kk = 0.15,
  dg = 0.1,
  dk = 0.1,
  dd = 0.15,
  gamma = 0.25,
  difficulty = NULL,
  base_rate = 0.25,
  seed = NULL
)

Arguments

n

Integer. Number of individuals to simulate.

n_items

Integer. Number of test items. Default 1.

gg

Numeric. Proportion: guess->guess (stable ignorance). Default 0.25.

gk

Numeric. Proportion: guess->know (learned). Default 0.15.

gd

Numeric. Proportion: guess->dk. Default 0.10.

kk

Numeric. Proportion: know->know (stable knowledge). Default 0.15.

dg

Numeric. Proportion: dk->guess. Default 0.10.

dk

Numeric. Proportion: dk->know (learned). Default 0.10.

dd

Numeric. Proportion: dk->dk. Default 0.15.

gamma

Numeric. Probability of guessing correctly. Can be scalar (same for all items) or vector of length n_items. Default 0.25.

difficulty

Numeric vector. Optional difficulty-link scores. If provided, gamma is computed as base_rate + (1 - base_rate) * plogis(-difficulty). Higher difficulty = harder item (lower gamma). Ignored if NULL.

base_rate

Numeric. Minimum guessing probability (random chance). Used when difficulty is specified. Default 0.25 (1/4 for 4-choice items).

seed

Optional integer. Random seed for reproducibility.

Details

The DK model has 7 latent classes representing transitions between guess (g), know (k), and don't know (d) states: - **gg**: guess both times - **gk**: guess -> know (learned) - **gd**: guess -> dk - **kk**: know -> know - **dg**: dk -> guess - **dk**: dk -> know (learned) - **dd**: dk -> dk

The know -> guess and know -> dk classes are absent by design. The model is identified by the assumption that people do not lose knowledge over a short informative process, which sets both to zero. Learning is gk + dk.

Parameters must sum to 1 (constraint enforced automatically).

When difficulty is specified, gamma values are derived using a logistic transformation: gamma_i = base_rate + (1 - base_rate) * plogis(-difficulty_i).

Value

List with two data frames:

pre

Pre-test responses (character: "0", "1", or "d")

post

Post-test responses (character: "0", "1", or "d")

Examples

# Simulate DK data
sim <- simulate_lca_dk(n = 5000, gk = 0.15, seed = 123)
fit <- item_lca_fit(sim$pre, sim$post)
fit$params["gk", ] # Should be close to 0.15

# Item-specific gamma (vector)
sim_vec <- simulate_lca_dk(n = 500, n_items = 3, gamma = c(0.2, 0.25, 0.3), seed = 456)

# Difficulty-link scores
sim_irt <- simulate_lca_dk(n = 500, n_items = 3, difficulty = c(1, 0, -1), seed = 789)

Standard Guessing Correction for Learning

Description

Estimate of learning adjusted with standard correction for guessing. Correction is based on number of options per question. The function takes separate pre-test and post-test dataframes. Why do we need dataframes? To accomodate multiple items. The items can carry NA (missing). Items must be in the same order in each dataframe. Assumes that respondents are posed same questions twice. The function also takes a lucky vector — the chance of getting a correct answer if guessing randomly. Each entry is 1/(number of options). The function also optionally takes a vector carrying names of the items. By default, the vector carrying adjusted learning estimates takes same item names as the pre_test items. However you can assign a vector of names separately via item_names.

Usage

stnd_cor(
  pre_test = NULL,
  pst_test = NULL,
  lucky = NULL,
  item_names = NULL,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test

Required. data.frame carrying responses to pre-test questions.

pst_test

Required. data.frame carrying responses to post-test questions.

lucky

Required. A vector. Each entry is 1/(number of options)

item_names

Optional. A vector carrying item names.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes it and '"error"' rejects it.

Value

a list of three vectors, carrying pre-treatment corrected scores, post-treatment scores, and adjusted estimates of learning

Examples

# Without DK
pre_test <- data.frame(item1 = c(1, 0, 0, 1, 0), item2 = c(1, NA, 0, 1, 0))
pst_test <- pre_test + cbind(c(0, 1, 1, 0, 0), c(0, 1, 0, 0, 1))
lucky <- rep(.25, 2)
stnd_cor(pre_test, pst_test, lucky)
# With DK
pre_test <- data.frame(item1 = c(1, 0, 0, 1, 0, "d", 0), item2 = c(1, NA, 0, 1, 0, "d", "d"))
pst_test <- data.frame(item1 = c(1, 0, 0, 1, 0, "d", 1), item2 = c(1, NA, 0, 1, 0, 1, "d"))
lucky <- rep(.25, 2)
stnd_cor(pre_test, pst_test, lucky)

Summary method for guess_cv

Description

Summary method for guess_cv

Usage

## S3 method for class 'guess_cv'
summary(object, ...)

Arguments

object

guess_cv object

...

ignored

Value

invisible summary


Summary method for guess_fit

Description

Summary method for guess_fit

Usage

## S3 method for class 'guess_fit'
summary(object, ...)

Arguments

object

guess_fit object

...

ignored

Value

invisible summary object


transmat: Cross-wave transition matrix

Description

Prints Cross-wave transition matrix and returns the vector behind the matrix. Missing values are treated as don't know responses by default. Set 'na_as = "missing"' when they instead represent structural missingness.

Usage

transmat(
  pre_test_var,
  pst_test_var,
  subgroup = NULL,
  force9 = FALSE,
  na_as = c("dk", "missing"),
  missing_action = c("omit", "error")
)

Arguments

pre_test_var

Required. A vector carrying pre-test scores of a particular item. Only

pst_test_var

Required. A vector carrying post-test scores of a particular item

subgroup

Optional. A Boolean vector indicating rows of the relevant subset.

force9

Optional. There are cases where DK data doesn't have DK. But we need the entire matrix. By default it is FALSE.

na_as

Classification of NA responses: '"dk"' (the default) treats them as observed don't know responses; '"missing"' treats them as structural missingness.

missing_action

How to handle structural missingness: '"omit"' excludes incomplete pairs and '"error"' rejects them.

Value

a numeric vector. Assume 1 denotes correct, 0 incorrect, and d/DK an observed don't know. When there is no don't know option and no missing, the entries are: x00, x10, x01, x11 When there is a don't know option, the entries of the vector are: x00, x10, xd0, x01, x11, xd1, xd0, x1d, xdd

Examples

pre_test_var <- c(1, 0, 0, 1, 0, 1, 0)
pst_test_var <- c(1, 0, 1, 1, 0, 1, 1)
transmat(pre_test_var, pst_test_var)

# With NAs
pre_test_var <- c(1, 0, 0, 1, "d", "d", 0, 1, NA)
pst_test_var <- c(1, NA, 1, "d", 1, 0, 1, 1, "d")
transmat(pre_test_var, pst_test_var)

Validate that two data frames have compatible dimensions

Description

Validate that two data frames have compatible dimensions

Usage

validate_compatible_dataframes(pre_test, pst_test)

Arguments

pre_test

pre-test data frame

pst_test

post-test data frame

Value

TRUE if valid, throws error otherwise


Validate that input is a data frame

Description

Validate that input is a data frame

Usage

validate_dataframe(x, arg_name)

Arguments

x

input to validate

arg_name

name of the argument for error messages

Value

TRUE if valid, throws error otherwise


Validate dk parameter (knowledge behind don't know responses)

Description

Validate dk parameter (knowledge behind don't know responses)

Usage

validate_dk(dk)

Arguments

dk

numeric value between 0 and 1

Value

TRUE if valid, throws error otherwise


Validate that vectors have equal length

Description

Validate that vectors have equal length

Usage

validate_equal_length(vec1, vec2, name1 = "vector1", name2 = "vector2")

Arguments

vec1

first vector

vec2

second vector

name1

name of first vector for error messages

name2

name of second vector for error messages

Value

TRUE if valid, throws error otherwise


Validate gamma parameter

Description

Validate gamma parameter

Usage

validate_gamma(gamma)

Arguments

gamma

probability parameter

Value

TRUE if valid, throws error otherwise


Validate lucky vector for standard correction

Description

Validate lucky vector for standard correction

Usage

validate_lucky_vector(lucky, n_items)

Arguments

lucky

vector of guessing probabilities

n_items

number of items to validate against

Value

TRUE if valid, throws error otherwise


Validate matrix input

Description

Validate matrix input

Usage

validate_matrix(x, arg_name, valid_ncols = NULL)

Arguments

x

input to validate

arg_name

name of the argument for error messages

valid_ncols

optional vector of valid column counts

Value

TRUE if valid, throws error otherwise


Validate prior parameters

Description

Validate prior parameters

Usage

validate_priors(priors, expected_length, param_name)

Arguments

priors

vector of prior parameters

expected_length

expected length of priors vector

param_name

name of parameter for error messages

Value

TRUE if valid, throws error otherwise


Validate Parameter Recovery via Monte Carlo Simulation

Description

Performs Monte Carlo simulations to assess parameter recovery of the LCA model. Useful for validating estimator performance.

Usage

validate_recovery(true_params, n = 500, n_items = 2, n_sims = 100, seed = NULL)

Arguments

true_params

Named numeric vector of true parameters. For no-DK model: c(gg=, gk=, kk=, gamma=) For DK model: c(gg=, gk=, gd=, kk=, dg=, dk=, dd=, gamma=)

n

Integer. Sample size per simulation. Default 500.

n_items

Integer. Number of items. Default 2.

n_sims

Integer. Number of Monte Carlo simulations. Default 100.

seed

Optional integer. Random seed for reproducibility.

Value

Data frame with one row per parameter containing columns: parameter (name), true_value, mean_estimate, bias (mean estimate minus true), rmse (root mean squared error), and se (Monte Carlo standard deviation of estimates).

Examples

## Not run: 
# Validate no-DK model recovery
results <- validate_recovery(
  c(gg = 0.35, gk = 0.30, kk = 0.35, gamma = 0.25),
  n = 500, n_sims = 50
)
print(results)

# Validate DK model recovery
results_dk <- validate_recovery(
  c(
    gg = 0.25, gk = 0.15, gd = 0.10, kk = 0.20,
    dg = 0.10, dk = 0.10, dd = 0.10, gamma = 0.25
  ),
  n = 500, n_sims = 50
)

## End(Not run)

Validate required parameters are not NULL

Description

Validate required parameters are not NULL

Usage

validate_required(...)

Arguments

...

named arguments to check

Value

TRUE if valid, throws error otherwise


Validate subgroup parameter

Description

Validate subgroup parameter

Usage

validate_subgroup(subgroup, expected_length)

Arguments

subgroup

logical vector for subsetting

expected_length

expected length to match

Value

TRUE if valid, throws error otherwise


Validate transition matrix values

Description

Validate transition matrix values

Usage

validate_transition_values(pre_test_var, pst_test_var)

Arguments

pre_test_var

pre-test variable vector

pst_test_var

post-test variable vector

Value

TRUE if valid, throws error otherwise


Constrain vector to [0,1] range

Description

Constrains values in a vector to be between 0 and 1. Used internally.

Usage

zero1(x)

Arguments

x

numeric vector to constrain

Value

numeric vector with values constrained to [0,1]