| Title: | Conditional Standard Error of Measurement Tools for Test Scores |
|---|---|
| Description: | Compute and compare conditional standard errors of measurement (CSEM) across score distributions using methods from classical test theory. Includes approaches for smoothing, bootstrapped CSEM, standardized CSEM, CSEM for scale scores, and assessment of properties of split-half scores. Also supports comparison with global standard errors derived from reliability coefficients and graphical visualization of CSEM curves and relative precision across observed score ranges. Some of these implemented methods are based on work by Lord (1955) <doi:10.1002/j.2333-8504.1955.tb00054.x>, Feldt and Qualls (1996) <doi:10.1111/j.1745-3984.1996.tb00486.x>, McNeish and Dumas (2025) <doi:10.3758/s13428-025-02611-8>. |
| Authors: | Cesar Merino-Soto [aut, cre] |
| Maintainer: | Cesar Merino-Soto <[email protected]> |
| License: | GPL-3 |
| Version: | 0.2.1 |
| Built: | 2026-10-13 11:34:35 UTC |
| Source: | https://github.com/cmerinos/csemtools |
Calculates Cronbach's alpha reliability coefficient for each test half separately, with bootstrap confidence intervals.
checkAlpha(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)checkAlpha(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame containing item scores for the first test half. |
half2 |
A numeric matrix or data frame containing item scores for the second test half. |
B |
Integer. Number of bootstrap resamples (default = 500). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE (default), rows with any missing values in either half are removed. |
Cronbach's alpha is computed as:
where is the number of items and is the average inter-item correlation.
Confidence intervals are estimated via percentile bootstrap.
A data frame with columns:
Half ("Half 1" or "Half 2"),
Coefficient ("alpha"),
Estimate (estimated alpha),
lwr.ci, upr.ci (bootstrap confidence interval).
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkAlpha(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkAlpha(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)
Calculates the Angoff-Feldt reliability coefficient for two test halves, which is appropriate when the halves may have unequal lengths. Confidence intervals are estimated via bootstrap.
checkAngoff(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)checkAngoff(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame containing item scores for the first test half. |
half2 |
A numeric matrix or data frame containing item scores for the second test half. |
B |
Integer. Number of bootstrap resamples (default = 500). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE (default), rows with any missing values in either half are removed. |
The Angoff coefficient (Angoff, 1953; Feldt, 2002) is defined as:
where and are the total scores of the two halves.
This coefficient is a generalization of the Spearman-Brown formula that does not require equal length halves. For equal lengths, it reduces to the usual Spearman-Brown reliability.
A data frame with columns:
Coefficient ("Angoff-Feldt"),
Estimate (estimated reliability),
lwr.ci, upr.ci (bootstrap percentile confidence interval).
Angoff, W. H. (1953). Test reliability and effective test length. Psychometrika, 18(1), 1-14. Feldt, L. S. (2002). Reliability estimation when a test is split into two parts of unknown effective length. Measurement in Education, 15(3), 295-308.
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkAngoff(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkAngoff(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)
Computes the Gilmer-Feldt congeneric reliability coefficient for each test half separately, with bootstrap confidence intervals. This is a lightweight alternative to McDonald's Omega, suitable for congeneric measures.
checkCongeneric(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)checkCongeneric(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame with item scores for the first half. |
half2 |
A numeric matrix or data frame with item scores for the second half. |
B |
Integer. Number of bootstrap resamples (default = 500). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE, rows with missing values are removed. |
The Gilmer-Feldt coefficient (Gilmer & Feldt, 1983) is a classical reliability estimator for congeneric tests, where items measure the same construct but may have different loadings. It is computed from the covariance matrix of the items using a weighting scheme that maximizes internal consistency.
Bootstrap confidence intervals are obtained via the percentile method.
A data frame with columns:
Half ("Half 1" or "Half 2"),
Coefficient ("Gilmer-Feldt"),
Estimate (estimated reliability),
lwr.ci, upr.ci (bootstrap confidence interval).
Gilmer, J. S., & Feldt, L. S. (1983). Reliability estimation for a test with parts of unknown lengths. Psychometrika, 48(1), 99-111.
set.seed(123) ## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkCongeneric(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)set.seed(123) ## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkCongeneric(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)
Evaluates distributional similarity between two test halves using:
Anderson-Darling test (from package kSamples) - optional,
Overlapping Index (OVI) based on kernel density estimation,
Kendall's W (concordance) derived from Spearman's rho.
checkDistribution(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)checkDistribution(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame for the first test half. |
half2 |
A numeric matrix or data frame for the second test half. |
B |
Integer. Number of bootstrap resamples for confidence intervals of OVI and Kendall's W (default = 500). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE, rows with missing values are removed. |
The Overlapping Index is computed as the area under the minimum of the two kernel density estimates (using Sheather-Jones bandwidth). The index ranges from 0 (no overlap) to 1 (identical distributions).
Kendall's W for two judges is derived from Spearman's rank correlation:
. It ranges from 0 (no agreement) to 1 (perfect agreement).
The Anderson-Darling test (from kSamples) tests the null hypothesis that the two distributions are identical. If the package is not installed, the test is skipped.
Effect sizes (ES):
Anderson-Darling: (standardised statistic).
OVI: the Overlapping Index itself.
Kendall's W: the W coefficient.
A data frame with columns:
Test, Statistic (test value, NA when not applicable),
p.value (only for AD), lwr.ci, upr.ci (only for OVI and W),
ES (effect size).
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkDistribution(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkDistribution(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)
Compares the central tendency of two test halves using Yuen's robust paired t-test (trimmed means) and computes the robust effect size (AKP) with confidence interval.
checkLocation(half1, half2, trim = 0.2, conf = 0.95, na.rm = TRUE)checkLocation(half1, half2, trim = 0.2, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame for the first test half. |
half2 |
A numeric matrix or data frame for the second test half. |
trim |
Proportion of observations to trim from each tail (default = 0.2). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE, rows with missing values are removed. |
The test statistic follows a t distribution with trimmed degrees of freedom.
The effect size (AKP) is defined as the trimmed mean difference divided by the
winsorized standard deviation of the differences (Algina, Keselman, & Penfield, 2005).
The confidence interval for the effect size is obtained using the noncentral t distribution
via the MBESS package. If MBESS is not installed, the CI is omitted
and a warning is issued.
A data frame with columns:
Test, Statistic, p.value,
lwr.ci, upr.ci (for trimmed mean difference),
ES, ES.lwr.ci, ES.upr.ci.
Yuen, K. K. (1974). The two-sample trimmed t for unequal population variances. Biometrika, 61(1), 165-170.
Algina, J., Keselman, H. J., & Penfield, R. D. (2005). An alternative to Cohen's standardized mean difference effect size: a robust parameter and confidence interval in the two independent groups case. Psychological methods, 10(3), 317-328. doi:10.1037/1082-989X.10.3.317
Algina, J., Keselman, H. J., & Penfield, R. D. (2005). Effect Sizes and their Intervals: The Two-Level Repeated Measures Case. Educational and Psychological Measurement, 65(2), 241-258. doi:10.1177/0013164404268675
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Location checkLocation(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Location checkLocation(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], conf = .95)
Evaluates differences in variability between two test halves using:
Log-transformed variability ratio (lnVR) with confidence interval.
Bonett-Seier test for equality of variances (robust to non-normality).
checkScale(half1, half2, conf = 0.95, na.rm = TRUE)checkScale(half1, half2, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame with scores from the first half. |
half2 |
A numeric matrix or data frame with scores from the second half. |
conf |
Numeric. Confidence level for lnVR interval (default = 0.95). |
na.rm |
Logical. If TRUE, rows with missing values are removed. |
A data frame with columns:
lnVR (log ratio of SDs), SE.lnVR, lwr.ci, upr.ci,
cor.halves (Pearson correlation between halves),
bs.stat (Bonett-Seier chi-square statistic),
bs.p (p-value for equality of variances),
n (effective sample size after NA removal).
Bonett, D. G., & Seier, E. (2002). Confidence intervals for variance and standard deviation ratios. Computational Statistics & Data Analysis, 40(3), 603-608.
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkScale(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkScale(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], conf = .95)
Calculates the Spearman-Brown reliability coefficient for two test halves and estimates confidence intervals using bootstrap resampling.
checkSpearmanBrown(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)checkSpearmanBrown(half1, half2, B = 500, conf = 0.95, na.rm = TRUE)
half1 |
A numeric matrix or data frame containing item scores for the first test half. |
half2 |
A numeric matrix or data frame containing item scores for the second test half. |
B |
Integer. Number of bootstrap resamples (default = 500). |
conf |
Numeric. Confidence level (default = 0.95). |
na.rm |
Logical. If TRUE (default), rows with any missing values in either half are removed. |
The Spearman-Brown coefficient is computed as:
where is the Pearson correlation between the total scores of the two halves.
Confidence intervals are estimated via percentile bootstrap.
A data frame with columns:
Coefficient ("Spearman-Brown"),
Estimate (estimated reliability),
lwr.ci, upr.ci (bootstrap confidence interval).
## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkSpearmanBrown(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)## Load data data("rse_data") ## Check split: difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## check Distribution checkSpearmanBrown(half1 = rse_data[,RSE.namesHalf$half1], half2 = rse_data[,RSE.namesHalf$half2], B = 1000, conf = .95)
Divides the items of a test into two halves using different methods.
checkSplit( data, method = c("ritc", "difficulty", "random", "optimized"), equal.size = TRUE, n_iter = 500, top_n = 10, seed = 123, na.rm = TRUE )checkSplit( data, method = c("ritc", "difficulty", "random", "optimized"), equal.size = TRUE, n_iter = 500, top_n = 10, seed = 123, na.rm = TRUE )
data |
A data frame or matrix of item responses (rows = persons, columns = items). |
method |
Character: "ritc", "difficulty", "random", or "optimized". |
equal.size |
Logical. If TRUE, forces halves to have the same number of items. |
n_iter |
Integer. Number of random splits when method = "optimized". |
top_n |
Integer. Number of top splits to report in summary when method = "optimized". |
seed |
Integer for reproducibility. |
na.rm |
Logical. If TRUE, removes rows with missing values. |
A list with components: half1, half2 (vectors of column names), summary (data frame), and method.
## Load data data("rse_data") ## Check split checkSplit(data = rse_data, method = "ritc") checkSplit(data = rse_data, method = "random") checkSplit(data = rse_data, method = "optimized") checkSplit(data = rse_data, method = "difficulty") ## Choosing split by difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") RSE.namesHalf$half1 RSE.namesHalf$half2## Load data data("rse_data") ## Check split checkSplit(data = rse_data, method = "ritc") checkSplit(data = rse_data, method = "random") checkSplit(data = rse_data, method = "optimized") checkSplit(data = rse_data, method = "difficulty") ## Choosing split by difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") RSE.namesHalf$half1 RSE.namesHalf$half2
Compares a conditional standard error of measurement (CSEM) function against the global (constant) SEM. The global SEM is computed from the observed score standard deviation and a reliability coefficient (e.g., alpha or omega). Optionally, confidence intervals for the global SEM can be obtained from user supplied reliability confidence bounds. The function produces a data frame with ratios and, if requested, plots of the CSEM vs. global SEM and/or the ratio.
compareCSEM( data, raw.score = "raw.score", CSEM = "CSEM", lwr.ci.CSEM = NULL, upr.ci.CSEM = NULL, score = NULL, csem = NULL, lwr.ci = NULL, upr.ci = NULL, cutoff = NULL, sd.score, reliability, reliab.lwrci = NULL, reliab.uprci = NULL, plot = c("none", "all", "csem", "ratio"), digits = 3, conf.level = 0.95, ... )compareCSEM( data, raw.score = "raw.score", CSEM = "CSEM", lwr.ci.CSEM = NULL, upr.ci.CSEM = NULL, score = NULL, csem = NULL, lwr.ci = NULL, upr.ci = NULL, cutoff = NULL, sd.score, reliability, reliab.lwrci = NULL, reliab.uprci = NULL, plot = c("none", "all", "csem", "ratio"), digits = 3, conf.level = 0.95, ... )
data |
A data frame containing at least the columns specified in
|
raw.score |
Character. Name of the column with observed scores (default = "raw.score"). |
CSEM |
Character. Name of the column with conditional SEM values (default = "CSEM"). |
lwr.ci.CSEM |
Character. Optional name of the column with lower confidence limits for CSEM. |
upr.ci.CSEM |
Character. Optional name of the column with upper confidence limits for CSEM. |
score |
Numeric vector of observed scores. If provided, overrides |
csem |
Numeric vector of conditional SEM values. If provided, overrides |
lwr.ci |
Numeric vector of lower confidence limits for CSEM (optional). |
upr.ci |
Numeric vector of upper confidence limits for CSEM (optional). |
cutoff |
Numeric vector of score values where vertical lines are added to the plots. Useful for highlighting cut scores or quantiles. Default = NULL. |
sd.score |
Numeric. Standard deviation of the observed scores (calculated externally from |
reliability |
Numeric. Reliability coefficient (e.g., alpha, omega, Gilmer-Feldt) used to compute global SEM. |
reliab.lwrci |
Numeric. Optional lower confidence bound for |
reliab.uprci |
Numeric. Optional upper confidence bound for |
plot |
Character. Type of plot to produce: |
digits |
Numeric. Number of decimal places for rounding output numeric columns (default = 3). |
conf.level |
Numeric. Confidence level for intervals (default = 0.95). Used only for labelling. |
... |
Additional arguments passed to |
The method for comparing conditional SEM against global SEM is inspired by the reliability representativeness approach described in McNeish and Dumas (2025), adapted here for standard errors of measurement rather than reliability.
The global SEM is defined as:
If reliability confidence bounds (reliab.lwrci, reliab.uprci) are supplied,
they are transformed to SEM bounds using the inverse relationship:
because lower reliability implies larger measurement error. These bounds are used to draw a confidence band around the global SEM line.
The ratio is computed as CSEM / SEM_global. Values above 1 indicate that the
conditional SEM is larger (worse precision) than the global average; values below 1
indicate better precision.
data: A data frame with columns raw.score, CSEM, optionally
lwr.ci.CSEM/upr.ci.CSEM, and ratio (rounded to digits).
global_sem: A data frame with two columns: value (label) and estimate
(numeric). Contains sem.global and, if provided, lwr.ci and upr.ci.
plot: A ggplot2 object (or list of two objects if plot = "all"); NULL if plot = "none".
McNeish, D., Dumas, D. (2025). Reliability representativeness: How well does coefficient alpha summarize reliability across the score distribution? Behavior Research Methods, 57, 93. doi:10.3758/s13428-025-02611-8
# Example using data frame df <- data.frame( raw.score = 10:40, CSEM = 2.3 + 0.005 * (10:40 - 25)^2, lwr.ci.CSEM = 2.1 + 0.005 * (10:40 - 25)^2, upr.ci.CSEM = 2.5 + 0.005 * (10:40 - 25)^2 ) result <- compareCSEM(data = df, sd.score = 6.0, reliability = 0.85, reliab.lwrci = 0.82, reliab.uprci = 0.88, plot = "all", cutoff = c(15, 30)) # Example using vectors directly scores <- 10:40 csem_vals <- 2.3 + 0.005 * (scores - 25)^2 compareCSEM(data = NULL, score = scores, csem = csem_vals, sd.score = 6.0, reliability = 0.85, plot = "csem")# Example using data frame df <- data.frame( raw.score = 10:40, CSEM = 2.3 + 0.005 * (10:40 - 25)^2, lwr.ci.CSEM = 2.1 + 0.005 * (10:40 - 25)^2, upr.ci.CSEM = 2.5 + 0.005 * (10:40 - 25)^2 ) result <- compareCSEM(data = df, sd.score = 6.0, reliability = 0.85, reliab.lwrci = 0.82, reliab.uprci = 0.88, plot = "all", cutoff = c(15, 30)) # Example using vectors directly scores <- 10:40 csem_vals <- 2.3 + 0.005 * (scores - 25)^2 compareCSEM(data = NULL, score = scores, csem = csem_vals, sd.score = 6.0, reliability = 0.85, plot = "csem")
Computes the Conditional Standard Error of Measurement (CSEM) under Lord's (1955, 1957) binomial error model. This formulation treats the test as a random sample of dichotomously scored items measuring a single ability. The method can be applied to both dichotomous and polytomous items by transforming raw scores into binomial-equivalent scores. Optionally, the function computes confidence intervals for the true number-correct score using either the classic CSEM-based method or the Wilson score method.
csemBinom( score.type = c("dich", "poly"), nitems, min.resp = NULL, max.resp = NULL, csem.method = c("Lord", "binom", "LordKeats"), data = NULL, rhoxx = NULL, ci = FALSE, ci.method = c("csem", "wilson"), conf.level = NULL, digits = 3, rho.report = FALSE )csemBinom( score.type = c("dich", "poly"), nitems, min.resp = NULL, max.resp = NULL, csem.method = c("Lord", "binom", "LordKeats"), data = NULL, rhoxx = NULL, ci = FALSE, ci.method = c("csem", "wilson"), conf.level = NULL, digits = 3, rho.report = FALSE )
score.type |
Character: |
nitems |
Integer. Number of items in the test. If |
min.resp |
Numeric. Minimum response value per item.
Required when |
max.resp |
Numeric. Maximum response value per item.
Required when |
csem.method |
Character: |
data |
Optional data frame or matrix of dichotomous (0/1) item responses.
Required for |
rhoxx |
Optional numeric value (0 < rhoxx < 1). An estimate of test reliability
(interpreted as KR-20). Used for |
ci |
Logical. If |
ci.method |
Character: |
conf.level |
Numeric vector of confidence levels (e.g., 0.95). Default |
digits |
Integer for rounding CSEM and confidence limits. Default 3. |
rho.report |
Logical. If |
Binomial error model (Lord, 1955, 1957):
Each examinee has true proportion-correct ; observed number-correct
is Binomial(,) with . Lord's estimator of the
conditional error variance is
and the CSEM is its square root. The options "Lord" and "binom" yield
numerically identical results.
Polytomous items:
Raw scores are linearly transformed to a proportion and then multiplied by
to obtain a binomial-equivalent score:
Lord-Keats method (csem.method = "LordKeats"):
Adjusts Lord's CSEM using the ratio .
If a data matrix is provided, KR-20 and KR-21 are computed directly.
If only rhoxx (interpreted as KR-20) is given, KR-21 is approximated as
0.8 * rhoxx following Wilson, Downing & Ebel (1979). This approximation works
for both dichotomous and polytomous (after transformation) cases.
Confidence intervals:
ci.method = "csem": equiv.score +/- z * CSEM.
ci.method = "wilson": Wilson interval for proportion .
If rho.report = FALSE (default), a data frame with rows for each possible
raw score. Columns: raw.score, prop.score, binom.CSEM, and for
score.type = "poly" also equiv.score. If ci = TRUE, additional
columns lwr.xx, upr.xx.
If rho.report = TRUE and csem.method = "LordKeats", a list with two
elements: csem_table (the data frame) and rho (a data frame containing
the reliability values used).
Lord, F. M. (1955). Estimating test reliability. Educational and Psychological Measurement, 15, 325-336. doi:10.1002/j.2333-8504.1955.tb00054.x
Lord, F. M. (1957). Do tests of the same length have the same standard error of measurement? Educational and Psychological Measurement, 17, 510-521. doi:10.1177/001316445701700407
Keats, J. A. (1957). Estimation of error variances of test scores. Psychometrika, 22(1), 29-41. doi:10.1177/001316445701700407
Wilson, R. A., Downing, S. M., & Ebel, R. L. (1979). An empirical adjustment of the Kuder-Richardson 21 reliability coefficient to better estimate the Kuder-Richardson 20 coefficient (ED173387). https://eric.ed.gov/?id=ED173387
# Dichotomous, Lord method csemBinom(score.type = "dich", nitems = 16, csem.method = "Lord") library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] # Lord-Keats method, more data csemBinom(score.type = "dich", nitems = 16, ci = TRUE, csem.method = "LordKeats", data = data.ability, rho.report = TRUE) # Lord-Keats method, no data csemBinom(score.type = "dich", nitems = 16, ci = FALSE, csem.method = "LordKeats", rhoxx = .86) # "LordKeats", polytomous items csemBinom(score.type = "poly", nitems = 10, min.resp = 0, max.resp = 4, ci = FALSE, csem.method = "LordKeats", rhoxx = .89)# Dichotomous, Lord method csemBinom(score.type = "dich", nitems = 16, csem.method = "Lord") library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] # Lord-Keats method, more data csemBinom(score.type = "dich", nitems = 16, ci = TRUE, csem.method = "LordKeats", data = data.ability, rho.report = TRUE) # Lord-Keats method, no data csemBinom(score.type = "dich", nitems = 16, ci = FALSE, csem.method = "LordKeats", rhoxx = .86) # "LordKeats", polytomous items csemBinom(score.type = "poly", nitems = 10, min.resp = 0, max.resp = 4, ci = FALSE, csem.method = "LordKeats", rhoxx = .89)
Estimates the conditional standard error of measurement for each total score using a non parametric bootstrap of items (tasks). This method simulates parallel test forms by resampling items with replacement and computes the standard deviation of the resulting bootstrap scores for each person. The individual standard errors are then averaged within each observed total score to obtain the conditional SEM. The procedure follows the logic of Colton, Gao, & Kolen (1996) but is adapted to continuous total scores (sum of Likert items) rather than discrete performance levels.
csemBoots( data, B = 500, cores = 1, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )csemBoots( data, B = 500, cores = 1, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )
data |
A data frame or matrix containing the item responses. Rows represent persons, columns represent items. Items can be dichotomous or polytomous (e.g., Likert scales). |
B |
Integer. Number of bootstrap replications (default = 500). |
cores |
Integer. Number of CPU cores to use for parallel processing.
If |
bin.score |
Integer or NULL. If an integer (e.g., 5), persons are grouped
into that many quantile groups based on their total score, and the average
CSEM within each group is reported. If |
smooth |
Logical. If |
degree |
Integer. Polynomial degree used when |
full.range |
Logical. If |
ci |
Logical. If |
conf.level |
Numeric. Confidence level for the intervals (default = 0.95). |
digits |
Integer. Number of decimal places for rounding the output. Default = 3. |
score.range |
Numeric vector of length 2 (min, max). Required when
|
na.rm |
Logical. If |
The observed total score is computed for each person as the sum of item responses.
For each bootstrap replication b = 1 ... B:
A bootstrap sample of items (columns) is drawn with replacement, preserving the original number of items.
For every person, the total score on the bootstrap item set is computed.
After all replications, each person has B bootstrap total scores.
The standard deviation of these B scores is the individual standard error
of measurement ().
Persons are grouped by their observed total score (from the original data).
Within each score level, the individual error variances are averaged, and the
square root is taken: .
Optionally, a polynomial smoothing is applied to the squared CSEM values to reduce sampling variability at score levels with few persons.
If bin.score is provided, the persons are divided into quantile groups
(based on the original total scores) and the average CSEM inside each group
is reported.
The standard error of measurement refers to the variability of a person's score across hypothetically parallel test forms. Resampling persons would simulate sampling from the population, not parallel forms. Resampling items creates different versions of the test, which is the correct approach to estimate the conditional error variance. This is the essence of the method used by Colton et al. (1996) for performance level scores, here extended to continuous total scores.
When cores = 1, the bootstrap runs sequentially and a progress bar is shown
via pbapply::pblapply. When cores > 1, a cluster is created using
parallel::makeCluster, the bootstrap is distributed with pbapply::pblapply
(which automatically displays a progress bar for parallel tasks), and the
cluster is stopped afterwards. The number of cores should not exceed the
available CPU cores.
Persons with any missing item responses are removed if na.rm = TRUE.
Score levels with fewer than 2 persons receive a missing CSEM (NA) in the raw
output; they are omitted from smoothing and from the full.range expansion
(except when full.range = TRUE and smooth = FALSE, where NAs are filled
by last observation carried forward).
A list with up to two elements:
A data frame with columns:
score : total score (integer).
n : number of persons with that score.
CSEM (or CSEM.smooth) : conditional standard error of measurement.
lwr.ci, upr.ci : confidence limits (if ci = TRUE).
If bin.score is provided, a data frame with:
group : quantile group number.
range : score range of the group.
n : number of persons in the group.
mean_score : average total score in the group.
CSEM.mean : average CSEM within the group.
lwr.ci, upr.ci : confidence limits (if ci = TRUE).
Colton, D. A., Gao, X., & Kolen, M. J. (1997). Assessing the reliability of performance level scores using bootstrapping. ACT Research Report Series, 97-3. Iowa City, 1A: ACT.
library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM with bootstrapping csemBoots(data.bfi.nmiss[, 1:5], B = 100, cores = 1) # CSEM with bootstrapping, smoothing, full range, CI csemBoots(data.bfi.nmiss[, 1:5], B = 100, smooth = TRUE, full.range = TRUE, score.range = c(10, 50), ci = TRUE, cores = 2) # Quantile groups (quintiles) csemBoots(data.bfi.nmiss[, 1:5], B = 100, smooth = TRUE, full.range = TRUE, score.range = c(10, 50), ci = TRUE, cores = 2, bin.score = 5)library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM with bootstrapping csemBoots(data.bfi.nmiss[, 1:5], B = 100, cores = 1) # CSEM with bootstrapping, smoothing, full range, CI csemBoots(data.bfi.nmiss[, 1:5], B = 100, smooth = TRUE, full.range = TRUE, score.range = c(10, 50), ci = TRUE, cores = 2) # Quantile groups (quintiles) csemBoots(data.bfi.nmiss[, 1:5], B = 100, smooth = TRUE, full.range = TRUE, score.range = c(10, 50), ci = TRUE, cores = 2, bin.score = 5)
Implements the improved method by Feldt & Qualls (1996) for estimating conditional
measurement error variance. The test is partitioned into n.parts (or as specified
by part_items). For each person, an unbiased estimate of the error variance
is computed from the part-test scores. These individual estimates are then
averaged within each total score group to obtain the CSEM.
This function does not apply smoothing; for the smoothed version (polynomial
regression) see csemMF.
csemFeldtQualls( data, n.parts = NULL, part_items = NULL, min.items.per.part = 2, bin.score = NULL, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )csemFeldtQualls( data, n.parts = NULL, part_items = NULL, min.items.per.part = 2, bin.score = NULL, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )
data |
A data frame or matrix with item responses (subjects in rows, items in columns). Items can be dichotomous or polytomous. |
n.parts |
Integer. Number of parts into which the test will be split
(by column order, as balanced as possible). Ignored if |
part_items |
Optional list. Each element is a character vector of column names
or an integer vector of column indices defining the items in that part.
If provided, |
min.items.per.part |
Integer. Minimum number of items per part (default 2). A warning is issued if any part has fewer items. |
bin.score |
Integer. Number of quantile groups (e.g., 5 for quintiles).
If |
full.range |
Logical. If |
ci |
Logical. If |
conf.level |
Numeric. Confidence level (default 0.95). |
digits |
Integer. Rounding for CSEM and confidence limits. Default 3. |
score.range |
Numeric vector of length 2 (min, max). Required for |
na.rm |
Logical. If |
A list with elements:
CSEM |
data.frame with columns |
binned.CSEM |
(if |
Feldt, L. S., & Qualls, A. L. (1996). Estimation of measurement error variance at specific score levels. Journal of Educational Measurement, 33(2), 141-156. doi:10.1111/j.1745-3984.1996.tb00486.x
library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM, Feldt-Qualls method csemFeldtQualls(data.bfi.nmiss[, 1:5]) # With Quantile groups (quintiles) csemFeldtQualls(bfi[, 1:5], n.parts = 2, bin.score = 5) # With ci = TRUE csemFeldtQualls(bfi[, 1:5], n.parts = 2, bin.score = 5, ci = TRUE, conf.level = .68)library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM, Feldt-Qualls method csemFeldtQualls(data.bfi.nmiss[, 1:5]) # With Quantile groups (quintiles) csemFeldtQualls(bfi[, 1:5], n.parts = 2, bin.score = 5) # With ci = TRUE csemFeldtQualls(bfi[, 1:5], n.parts = 2, bin.score = 5, ci = TRUE, conf.level = .68)
Estimates conditional standard errors of measurement using the variance-components approach described in Feldt, Steffen, & Gupta (1985). This is the method referred to as "ANOVA" in the JASP Reliability module.
For each unique total score (or quantile group), the CSEM is computed as:
where is the number of items and is the sample variance
of item within the group (using divisor ).
The function offers polynomial smoothing (smooth = TRUE) and expansion to
a full range of integer scores (full.range = TRUE). It also allows
aggregation into quantile groups (bin.score).
csemFSG( data, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )csemFSG( data, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )
data |
A data frame or matrix with item responses (subjects in rows, items in columns). Items can be dichotomous or polytomous. |
bin.score |
integer. Number of quantile groups (e.g., 5 for quintiles).
If |
smooth |
logical. If |
degree |
integer. Polynomial degree used when |
full.range |
logical. If |
ci |
logical. If |
conf.level |
numeric. Confidence level for intervals (default 0.95). |
digits |
integer. Rounding for CSEM and confidence limits. Default = 3. |
score.range |
numeric vector of length 2 (min, max). Required when
|
na.rm |
logical. If |
A list with elements:
CSEM |
data.frame with columns |
binned.CSEM |
(if |
Feldt, L. S., Steffen, M., & Gupta, N. C. (1985). A comparison of five methods for estimating the standard error of measurement at specific score levels. Applied Psychological Measurement, 9(4), 351-361.
library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM, Feldt, Steffen, & Gupta method, no smooting csemFSG(bfi[, 1:5]) # with smooting csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2) # with binned score (quntiles) csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2, bin.score = 5) # add confidence intervals csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2, bin.score = 5, ci = TRUE, conf.level = .68)library(psych) # Loading data data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM, Feldt, Steffen, & Gupta method, no smooting csemFSG(bfi[, 1:5]) # with smooting csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2) # with binned score (quntiles) csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2, bin.score = 5) # add confidence intervals csemFSG(bfi[, 1:5], smooth = TRUE, degree = 2, bin.score = 5, ci = TRUE, conf.level = .68)
Implements the Mollenkopf-Feldt method, which applies polynomial regression to the individual error variance estimates from Feldt & Qualls (1996). This provides smoothed CSEM values along the score scale.
csemMF( data, n.parts = NULL, part_items = NULL, min.items.per.part = 2, degree = 2, bin.score = NULL, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )csemMF( data, n.parts = NULL, part_items = NULL, min.items.per.part = 2, degree = 2, bin.score = NULL, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )
data |
A data frame or matrix with item responses (subjects in rows, items in columns). |
n.parts |
Integer. Number of parts into which the test will be split
(by column order, as balanced as possible). Ignored if |
part_items |
Optional list. Each element is a character vector of column names
or an integer vector of column indices defining the items in that part.
If provided, |
min.items.per.part |
Integer. Minimum number of items per part (default 2). A warning is issued if any part has fewer items. |
degree |
Integer. Degree of the polynomial (default 2). |
bin.score |
Integer. Number of quantile groups (e.g., 5 for quintiles).
If |
full.range |
Logical. If |
ci |
Logical. If |
conf.level |
Numeric. Confidence level (default 0.95). |
digits |
Integer. Rounding for output. |
score.range |
Numeric vector length 2. Required if |
na.rm |
Logical. Remove rows with missing values. |
A list with elements:
CSEM |
data.frame with columns |
binned.CSEM |
(if |
Mollenkopf, W. G. (1949). Variation of the standard error of measurement. Psychometrika, 14(3), 189-229. Feldt, L. S., & Qualls, A. L. (1996). Estimation of measurement error variance at specific score levels. Journal of Educational Measurement, 33(2), 141-156.
#Basic use ## Load data data("rse_data") ## Split in two halves RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## Items in the halves? RSE.namesHalf$half1 RSE.namesHalf$half2 ## Run Mollenkoptf-Feldt method csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 2) ## 3 parts csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 3) ## CSEM for binned score too csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 2, bin.score = 4) ## Full report csemMF(data = rse_data, ci = FALSE, conf.level = .90, degree = 3, n.parts = 2, bin.score = 4)#Basic use ## Load data data("rse_data") ## Split in two halves RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") ## Items in the halves? RSE.namesHalf$half1 RSE.namesHalf$half2 ## Run Mollenkoptf-Feldt method csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 2) ## 3 parts csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 3) ## CSEM for binned score too csemMF(data = rse_data, ci = FALSE, degree = 3, n.parts = 2, bin.score = 4) ## Full report csemMF(data = rse_data, ci = FALSE, conf.level = .90, degree = 3, n.parts = 2, bin.score = 4)
Computes conditional standard errors of measurement (CSEM) under Lord's strong true score theory (compound binomial model) for dichotomously scored items. The estimator follows Lord (1965) as summarized by Tong and Kolen (2018). Optionally, the function computes confidence intervals for the true number-correct score.
csemStrong( data, score.type = c("dich", "poly"), nitems = NULL, min.resp = NULL, max.resp = NULL, bin.score = NULL, ci = FALSE, ci.method = c("csem", "wilson"), conf.level = NULL, digits = 3, full.range = TRUE, score.range = NULL, summary = FALSE, na.rm = TRUE )csemStrong( data, score.type = c("dich", "poly"), nitems = NULL, min.resp = NULL, max.resp = NULL, bin.score = NULL, ci = FALSE, ci.method = c("csem", "wilson"), conf.level = NULL, digits = 3, full.range = TRUE, score.range = NULL, summary = FALSE, na.rm = TRUE )
data |
A numeric matrix or data frame with examinees in rows and
items in columns. For |
score.type |
Character: |
nitems |
Optional integer. Number of items. If |
min.resp |
Numeric. Minimum response value per item.
Required when |
max.resp |
Numeric. Maximum response value per item.
Required when |
bin.score |
Integer. Number of quantile groups (e.g., 5 for quintiles).
If |
ci |
Logical. If |
ci.method |
Character: |
conf.level |
Numeric vector of confidence levels (e.g., 0.95).
Default |
digits |
Integer for rounding CSEM and confidence limits. Default 3. |
full.range |
Logical. If |
score.range |
Optional numeric vector of length 2 (min, max). If provided, confidence intervals are truncated to this range. If NULL, the observed score range (or theoretical range for full.range) is used. |
summary |
Logical. If |
na.rm |
Logical. If |
A list with components:
CSEM |
Data frame with columns: |
binned.CSEM |
(if |
summary |
(if |
Lord, F. M. (1965). A strong true score theory, with applications. Psychometrika, 30, 239-270. doi:10.1007/BF02289490
Tong, Y. and Kolen, M.J. (2018). Conditional Standard Errors of Measurement. In Wiley StatsRef: Statistics Reference Online (eds N. Balakrishnan, T. Colton, B. Everitt, W. Piegorsch, F. Ruggeri and J.L. Teugels; pp. 1-8). doi:10.1002/9781118445112.stat06376.pub2
# Dichotomous, strong true score library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = TRUE, summary = FALSE) # Dichotomous, Compound Binomial Model (strong true score), more summary and binned score csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = FALSE, summary = TRUE, bin.score = 5)# Dichotomous, strong true score library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = TRUE, summary = FALSE) # Dichotomous, Compound Binomial Model (strong true score), more summary and binned score csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = FALSE, summary = TRUE, bin.score = 5)
Simplified version without manual merging of small groups.
Use smooth = TRUE for stable estimates across the whole score range.
When smooth = FALSE and full.range = TRUE, missing values (NA) are
filled with the last valid observation (carried forward) for better readability.
csemThorndike( half1, half2, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )csemThorndike( half1, half2, bin.score = NULL, smooth = FALSE, degree = 2, full.range = FALSE, ci = FALSE, conf.level = 0.95, digits = 3, score.range = NULL, na.rm = TRUE )
half1 |
data.frame/matrix with first half items. |
half2 |
data.frame/matrix with second half items. |
bin.score |
integer (number of quantile groups) or NULL (individual scores). |
smooth |
logical. If TRUE, applies polynomial smoothing. |
degree |
integer. Polynomial degree (used if smooth=TRUE). |
full.range |
logical. If TRUE, report all integer scores from
|
ci |
logical. If TRUE, compute confidence intervals for true score. |
conf.level |
numeric. Confidence level (default 0.95). |
digits |
integer. Rounding for output. |
score.range |
numeric vector of length 2 (min, max). Required for full.range=TRUE. Also used to truncate confidence intervals (if ci=TRUE). |
na.rm |
Logical. If TRUE, missing values in items are ignored when computing
half-test totals (passed to |
A list with elements:
CSEM |
data.frame with columns |
binned.CSEM |
(if bin.score is integer) data.frame with quantile groups. |
Thorndike, R. L. (1951). Reliability. In E. F. Lindquist (Ed.), Educational measurement (pp. 560-620). American Council on Education.
Lee, W., & Harris, D. J. (2025). Reliability in educational measurement. In L. L. Cook & M. J. Pitoniak (Eds.), Educational measurement (5th ed., pp. 277-381). Oxford University Press. doi:10.1093/oso/9780197654965.003.0005
## Load data data("rse_data") ## Choosing split by difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") RSE.namesHalf$half1 RSE.namesHalf$half2 # Thorndike csem, basic ouput csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = FALSE, ci = FALSE) # Thorndike csem, smoothing and binned score csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = TRUE, degree = 2, ci = FALSE, bin.score = 5) # Thorndike csem, smoothing, binned score, and confidence interval csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = TRUE, degree = 2, ci = TRUE, conf.level = .90, bin.score = 5)## Load data data("rse_data") ## Choosing split by difficulty criteria RSE.namesHalf <- checkSplit(data = rse_data, method = "difficulty") RSE.namesHalf$half1 RSE.namesHalf$half2 # Thorndike csem, basic ouput csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = FALSE, ci = FALSE) # Thorndike csem, smoothing and binned score csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = TRUE, degree = 2, ci = FALSE, bin.score = 5) # Thorndike csem, smoothing, binned score, and confidence interval csemThorndike(half1 = rse_data[, RSE.namesHalf$half1], half2 = rse_data[, RSE.namesHalf$half2], smooth = TRUE, degree = 2, ci = TRUE, conf.level = .90, bin.score = 5)
This function compares two CSEM curves (or two methods) using:
Polynomial regression with interaction to assess global differences.
Point-wise effect sizes (CSEM ratio) with confidence intervals.
Point-wise hypothesis tests with multiple comparison correction (if sample sizes are provided).
curvesCSEMcomp( score, csem.m1, csem.m2, n.m1 = NULL, n.m2 = NULL, name.m1 = NULL, name.m2 = NULL, poly.degree = 3, nboot = 1000, seed = 123, adjust.method = "fdr", alpha = 0.05, conf.level = 0.95, plot = FALSE, plot.type = c("csem", "var"), plot.theme = NULL )curvesCSEMcomp( score, csem.m1, csem.m2, n.m1 = NULL, n.m2 = NULL, name.m1 = NULL, name.m2 = NULL, poly.degree = 3, nboot = 1000, seed = 123, adjust.method = "fdr", alpha = 0.05, conf.level = 0.95, plot = FALSE, plot.type = c("csem", "var"), plot.theme = NULL )
score |
Numeric vector of scores (common axis). Must be increasing. |
csem.m1 |
Vector of CSEM for method/group 1. |
csem.m2 |
Vector of CSEM for method/group 2. |
n.m1 |
Vector of sample sizes for method/group 1 (optional, required for tests and CIs). |
n.m2 |
Vector of sample sizes for method/group 2 (optional). |
name.m1 |
Name of method/group 1 (optional; if NULL, inferred from object). |
name.m2 |
Name of method/group 2 (optional). |
poly.degree |
Degree of polynomial regression (default 3). |
nboot |
Number of bootstrap replicates for global ratio CI (default 1000, only used if n provided). |
seed |
Random seed for reproducibility (default 123). |
adjust.method |
Method for multiple comparison correction (default "fdr"). See |
alpha |
Significance level for significant regions (default 0.05). |
conf.level |
Confidence level for intervals (default 0.95). |
plot |
Logical; if TRUE generates plots (default FALSE). |
plot.type |
Type of plot: "csem" (CSEM ratio with CI and significant regions) or "var" (variance ratio with CI and significant regions). Default "csem". |
plot.theme |
A ggplot2 theme object (optional). If NULL, |
The statistical tests are based on the error variances (CSEM^2) because they are additive and their sampling variance has a closed form:
The standard error of the difference between two independent variances is:
Confidence intervals for the ratio of CSEM are obtained by taking the square root of the variance-ratio confidence limits (after applying the log transformation).
A list with components:
csem.compareData frame with score, CSEM values, difference, ratio, and confidence limits (CSEM scale).
var.compareData frame with variance components, difference, ratio, standard errors, z-statistics, p-values (raw and adjusted), significance flag, and confidence limits (variance scale).
global.effectData frame with global summaries: geometric mean ratios and mean differences for both CSEM and variance, with bootstrap CIs.
regressionList with ANOVA table, fit statistics (R^2, adjusted ^2), and coefficient table (estimates, SE, t, p, CI).
significant.regionsData frame with intervals where adjusted p-value < alpha (if n provided).
alphaThe significance level used.
conf.levelThe confidence level used.
# Simulated example without sample sizes, and non plot score <- seq(0, 100, length = 50) csem1 <- 1 + 0.02*score + rnorm(50, 0, 0.1) csem2 <- 1.2 + 0.015*score + rnorm(50, 0, 0.1) res <- curvesCSEMcomp(score, csem1, csem2, name.m1 = "Method A", name.m2 = "Method B") # With sample sizes (to get tests and CIs) res2 <- curvesCSEMcomp(score, csem1, csem2, n.m1 = rep(30,50), n.m2 = rep(30,50), plot = TRUE, plot.type = "csem", alpha = 0.01) # Global effect output res2$global.effect # Output in score-point level res2$csem.compare res2$var.compare# Simulated example without sample sizes, and non plot score <- seq(0, 100, length = 50) csem1 <- 1 + 0.02*score + rnorm(50, 0, 0.1) csem2 <- 1.2 + 0.015*score + rnorm(50, 0, 0.1) res <- curvesCSEMcomp(score, csem1, csem2, name.m1 = "Method A", name.m2 = "Method B") # With sample sizes (to get tests and CIs) res2 <- curvesCSEMcomp(score, csem1, csem2, n.m1 = rep(30,50), n.m2 = rep(30,50), plot = TRUE, plot.type = "csem", alpha = 0.01) # Global effect output res2$global.effect # Output in score-point level res2$csem.compare res2$var.compare
Computes the Kuder-Richardson formula 20 (KR-20) reliability coefficient for a test with dichotomously scored (0/1) items. This is a measure of internal consistency.
kr20(data)kr20(data)
data |
A data frame or matrix of dichotomous (0/1) item responses, with rows as persons and columns as items. |
The KR-20 formula is:
where is the number of items, is the proportion correct
on item , , and is the variance
of the total test scores (using population variance divisor ).
Rows with missing values are removed using na.omit.
A single numeric value: the KR-20 reliability coefficient.
Computes the Kuder-Richardson formula 21 (KR-21) reliability coefficient, a simplified version of KR-20 that assumes equal item difficulties. It is easier to compute but generally underestimates KR-20.
kr21(data)kr21(data)
data |
A data frame or matrix of dichotomous (0/1) item responses, with rows as persons and columns as items. |
The KR-21 formula is:
where is the number of items, is the mean total score,
and is the variance of total scores (population variance).
Rows with missing values are removed using na.omit.
A single numeric value: the KR-21 reliability coefficient.
Creates a ggplot2 plot of the CSEM as a function of test scores, or a plot of the observed score with confidence interval band for the true score.
plotCSEM( score, csem, lwr.ci = NULL, upr.ci = NULL, plot.type = c("csem", "csemscore"), cutoff = NULL, title = NULL, xlab = NULL, ylab = NULL, color.line = "black", color.points = "darkred", color.band = "lightblue", color.cutoff = "gray50", line.type = "solid", point.size = 2, save.path = NULL, width = 8, height = 6 )plotCSEM( score, csem, lwr.ci = NULL, upr.ci = NULL, plot.type = c("csem", "csemscore"), cutoff = NULL, title = NULL, xlab = NULL, ylab = NULL, color.line = "black", color.points = "darkred", color.band = "lightblue", color.cutoff = "gray50", line.type = "solid", point.size = 2, save.path = NULL, width = 8, height = 6 )
score |
Numeric vector of scores (x-axis). |
csem |
Numeric vector of CSEM values (y-axis for |
lwr.ci |
Numeric vector of lower confidence limits (required for |
upr.ci |
Numeric vector of upper confidence limits (required for |
plot.type |
Character: |
cutoff |
Numeric vector of score values where vertical lines are added. Useful for highlighting cut scores or quantiles. Default = NULL. |
title |
Character. Plot title. If NULL, a default title is generated. |
xlab |
Character. X-axis label. If NULL, defaults to "Score". |
ylab |
Character. Y-axis label. If NULL, auto-generated. |
color.line |
Color for the line (default = "black"). |
color.points |
Color for points (default = "darkred"). |
color.band |
Color for confidence band/ribbon (default = "lightblue"). |
color.cutoff |
Color for cutoff lines (default = "gray50"). |
line.type |
Line type (default = "solid"). |
point.size |
Size of points (default = 2). |
save.path |
Optional file path to save plot as PNG. If NULL, plot is not saved. |
width |
Numeric. Width of saved plot in inches (default = 8). |
height |
Numeric. Height of saved plot in inches (default = 6). |
A ggplot2 object (invisibly). The plot is also printed.
basicData <- csemBinom(score.type = "dich", nitems = 10) plotCSEM(score = basicData$raw.score, csem = basicData$binom.CSEM) # Example with simulated data scores <- 0:20 csem_vals <- 1 + 0.5 * abs(scores - 10) / 10 # CSEM curve plotCSEM(score = scores, csem = csem_vals, plot.type = "csem") # Confidence band for true score (needs lwr.ci and upr.ci) lwr <- scores - 1.96 * csem_vals upr <- scores + 1.96 * csem_vals plotCSEM(score = scores, csem = scores, lwr.ci = lwr, upr.ci = upr, plot.type = "csemscore", cutoff = c(5, 10, 15))basicData <- csemBinom(score.type = "dich", nitems = 10) plotCSEM(score = basicData$raw.score, csem = basicData$binom.CSEM) # Example with simulated data scores <- 0:20 csem_vals <- 1 + 0.5 * abs(scores - 10) / 10 # CSEM curve plotCSEM(score = scores, csem = csem_vals, plot.type = "csem") # Confidence band for true score (needs lwr.ci and upr.ci) lwr <- scores - 1.96 * csem_vals upr <- scores + 1.96 * csem_vals plotCSEM(score = scores, csem = scores, lwr.ci = lwr, upr.ci = upr, plot.type = "csemscore", cutoff = c(5, 10, 15))
Fits polynomial models of degree 1 to max_degree to the data (x, y)
and returns a table containing information criteria (AIC, BIC), adjusted R^2,
and the significance of the term of the highest degree. This helps in choosing the appropriate degree
to use in csemFeldt(..., smooth = TRUE, degree = ...).
polynomialDegree( x, y, min_degree = 1, max_degree = 6, show.coefs = FALSE, plot = FALSE )polynomialDegree( x, y, min_degree = 1, max_degree = 6, show.coefs = FALSE, plot = FALSE )
x |
Numeric vector of scores (cluster centers). |
y |
Numeric vector of CSEM.raw (unsmoothed estimates). |
min_degree |
Minimum degree to evaluate (default 1). |
max_degree |
Maximum degree to evaluate (default 6). |
show.coefs |
If TRUE, displays the coefficients for each model. |
plot |
If TRUE, generates a plot of AIC and BIC versus degree. |
A list containing:
summary |
A data.frame with degrees of freedom, AIC, BIC, adjusted R^2, p-value of the term with the highest degrees of freedom (compared to the previous model), and whether the degrees of freedom are "better" according to AIC or BIC. |
models |
A list of |
set.seed(123) x <- 0:20 y <- 2 + 0.5*x - 0.02*x^2 + rnorm(21, sd=0.2) res <- polynomialDegree(x, y, max_degree = 4, plot = TRUE) print(res$summary)set.seed(123) x <- 0:20 y <- 2 + 0.5*x - 0.02*x^2 + rnorm(21, sd=0.2) res <- polynomialDegree(x, y, max_degree = 4, plot = TRUE) print(res$summary)
Print method for csem_compare objects
## S3 method for class 'csem_compare' print(x, details = FALSE, ...)## S3 method for class 'csem_compare' print(x, details = FALSE, ...)
x |
An object of class |
details |
Logical; if |
... |
Additional arguments passed to |
A data frame with 800 observations on 10 items from the Rosenberg Self-Esteem Scale. Negatively worded items were reverse scored.
rse_datarse_data
A data frame with 800 rows and 10 variables.
Adapted from the archived package EFA.dimensions v0.1.8.8.
Rosenberg, M. (1965). Society and the Adolescent Self-Image. Princeton University Press.
head(rse_data)head(rse_data)
Applies the formal methodologies proposed by Feldt and Qualls (1998) to translate raw score CSEMs into non-linear scale score metrics. Supports both the calculus-based Polynomial Method (using monotonic splines) and the interval-based Approximation Method.
scaleCSEM( raw, scale, csem, method = c("approx", "polym"), C = NULL, plot = FALSE, plot.what = "both" )scaleCSEM( raw, scale, csem, method = c("approx", "polym"), C = NULL, plot = FALSE, plot.what = "both" )
raw |
Numeric vector. Raw scores (must be integer values, ideally consecutive). |
scale |
Numeric vector. Scale scores corresponding to each raw score. |
csem |
Numeric vector. Conditional standard errors of measurement in raw score units. |
method |
Character. "approx" (interval method) or "polym" (monotonic spline method). |
C |
Integer. Interval width for "approx". If NULL, uses round(1.5 * mean(csem)). |
plot |
Logical. If TRUE, generates a plot. |
plot.what |
Character. "both", "raw", or "scale" to choose what to display. |
Important technical notes:
Use of SCAM in the "polym" method: This method uses the scam package
(Shape Constrained Additive Models) with a monotonic increasing P-spline basis
(bs = "mpi"). This choice mathematically enforces a strictly non-negative
first derivative across the entire raw score range, matching the psychometric
requirement stated by Feldt & Qualls (1998, p. 163). Unconstrained splines
(smooth.spline) or high-degree polynomials can produce negative slopes
at the boundaries, leading to invalid negative scale score standard errors.
The scam approach avoids arbitrary post-hoc adjustments.
Note: The scam package requires mgcv, which will be installed
automatically when you install scam.
Completeness of the conversion table (method "approx"): This method
directly looks up the scale scores associated with in the provided
vectors. Therefore, it is mandatory that the raw vector contains all integer values
required to cover for every row within the observed range of raw scores.
Ideally, the table should include all integer raw scores from the minimum to the maximum
observed. If any required raw score is missing, the function stops with an informative error.
No interpolation is performed.
Dependencies:
The "polym" method requires the scam package (which in turn depends on mgcv).
Please ensure both are installed:
install.packages(c("scam", "mgcv")).
If these packages are not available, use method = "approx" instead.
Range of raw scores:
The function does not assume that raw scores start at 0. It uses the minimum and maximum values
present in the raw vector as the natural boundaries of the score scale. This makes it
suitable for Likert-type scales (e.g., summing 5 items each scored 1-5 gives a minimum of 5).
Internally, the intervals are truncated to the observed range .
A data.frame with columns: raw, scale, csem, slope, scale_csem.
Feldt, L. S., & Qualls, A. L. (1998). Approximating Scale Score Standard Error of Measurement From the Raw Score Standard Error. Applied Measurement in Education, 11(2), 159-177.
# Example with linear transformation (slope = 5) raw <- 0:10 scale <- seq(20, 70, by = 5) csem <- c(2.0, 1.8, 1.6, 1.4, 1.3, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0) scaleCSEM(raw, scale, csem, method = "approx", plot = TRUE) # Simulate a nonlinear scale (example: square root) raw <- 0:10 scale <- round(20 + 30 * sqrt(raw/10)) # no lineal csem <- c(2.0, 1.8, 1.6, 1.4, 1.3, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0) scaleCSEM(raw, scale, csem, method = "approx", plot = TRUE) # Full workflow # Loading data library(psych) data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM with bootstrapping output.boots1 <- csemBoots(data = data.bfi.nmiss[,1:5], ci = FALSE, conf.level = .90, full.range = TRUE, score.range = c(5, 30), smooth = TRUE, B = 2000) # Score sum uno <- table(rowSums(data.bfi.nmiss[,1:5])) # t Scores, linear transformation dos <- table(round(psych::rescale(x = rowSums(data.bfi.nmiss[,1:5]), mean = 50, sd = 10))) # merge ot dataframe dframe <- cbind.data.frame(score = as.data.frame(uno)$Var1, tScore = as.data.frame(dos)[1]) colnames(dframe)[2] <- "tscore" scaleCSEM(raw = output.boots1$CSEM$score, scale = as.numeric(dframe$tscore), csem = output.boots1$CSEM$CSEM.smooth, method = "polym", C = 5,plot = TRUE, plot.what = "both")# Example with linear transformation (slope = 5) raw <- 0:10 scale <- seq(20, 70, by = 5) csem <- c(2.0, 1.8, 1.6, 1.4, 1.3, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0) scaleCSEM(raw, scale, csem, method = "approx", plot = TRUE) # Simulate a nonlinear scale (example: square root) raw <- 0:10 scale <- round(20 + 30 * sqrt(raw/10)) # no lineal csem <- c(2.0, 1.8, 1.6, 1.4, 1.3, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0) scaleCSEM(raw, scale, csem, method = "approx", plot = TRUE) # Full workflow # Loading data library(psych) data("bfi") # Choosing variables data.bfi <- bfi[, c("N1", "N2", "N3", "N4", "N5", "gender", "age")] # Clean for missing values data.bfi.nmiss <- data.bfi[complete.cases(data.bfi), ] # CSEM with bootstrapping output.boots1 <- csemBoots(data = data.bfi.nmiss[,1:5], ci = FALSE, conf.level = .90, full.range = TRUE, score.range = c(5, 30), smooth = TRUE, B = 2000) # Score sum uno <- table(rowSums(data.bfi.nmiss[,1:5])) # t Scores, linear transformation dos <- table(round(psych::rescale(x = rowSums(data.bfi.nmiss[,1:5]), mean = 50, sd = 10))) # merge ot dataframe dframe <- cbind.data.frame(score = as.data.frame(uno)$Var1, tScore = as.data.frame(dos)[1]) colnames(dframe)[2] <- "tscore" scaleCSEM(raw = output.boots1$CSEM$score, scale = as.numeric(dframe$tscore), csem = output.boots1$CSEM$CSEM.smooth, method = "polym", C = 5,plot = TRUE, plot.what = "both")
Given vectors of reference scores and their CSEM values, this function matches each individual score exactly to a reference score. If an individual score is not found in the reference, a warning is issued and NA is returned. Optionally, it computes confidence intervals assuming normality.
scoreCSEM(score.indiv, score.ref, csem, ci = FALSE, conf.level = 0.95)scoreCSEM(score.indiv, score.ref, csem, ci = FALSE, conf.level = 0.95)
score.indiv |
Numeric vector of individual scores. |
score.ref |
Numeric vector of reference scores (e.g., from a CSEM table). |
csem |
Numeric vector of CSEM values corresponding to |
ci |
Logical. If |
conf.level |
Numeric. Confidence level (default 0.95). |
A data frame with the same number of rows as length(score.indiv),
containing columns: score.indiv, CSEM, and if ci = TRUE, lwr and upr.
# Use data library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] # get CSEM deom Binomial model res <- csemStrong(data.ability, score.type = "dich", nitems = 16) # Get CSEM for scores 5, 8, 12 from a strong CSEM table scoreCSEM(score.indiv = c(5, 8, 12), score.ref = res$CSEM$raw.score, csem = res$CSEM$csem.strong, ci = TRUE)# Use data library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] # get CSEM deom Binomial model res <- csemStrong(data.ability, score.type = "dich", nitems = 16) # Get CSEM for scores 5, 8, 12 from a strong CSEM table scoreCSEM(score.indiv = c(5, 8, 12), score.ref = res$CSEM$raw.score, csem = res$CSEM$csem.strong, ci = TRUE)
Computes examinee-level (or score-level) reliability from conditional standard errors of measurement (CSEM) and the total observed score variance.
stdCSEM(csem, var_obs, na.rm = FALSE)stdCSEM(csem, var_obs, na.rm = FALSE)
csem |
Numeric vector of conditional standard errors (e.g., from |
var_obs |
Numeric. Variance of the observed total scores. |
na.rm |
Logical. If TRUE, missing values in |
The standardized conditional reliability for each score level (or examinee) is:
where is the variance of observed scores in the sample.
Values are truncated to the 0 to 1 interval.
"A related precedent appears in Lawrence (1995, Equation 1). The adaptation by Raju et al. (2007) lies in substituting the global SEM with the CSEM vector, while keeping the total observed variance constant in the denominator to preserve the classical reliability metric."
A numeric vector of the same length as csem (or shorter if na.rm = TRUE),
with reliability estimates rounded to 3 decimal places.
Raju, N. S., Price, L. R., Oshima, T. C., & Nering, M. L. (2007). Standardized conditional SEM: A comparison of methods. Educational and Psychological Measurement, 67(6), 903-916. doi:10.1177/0146621606291569
Lawrence, I. M. (1995). ESTIMATING RELIABILITY FOR TESTS COMPOSED OF ITEM SETS. ETS Research Report Series, 1995(1). doi:10.1002/j.2333-8504.1995.tb01653.x
# Sample of values csem_vals <- c(2.0, 2.5, 3.0) var_obs <- 25 stdCSEM(csem_vals, var_obs) #From Strong true score model library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] strongCSEM.out <- csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = TRUE, summary = TRUE) # Looking ouput strongCSEM.out # Standardized CSEM stdCSEM(csem = strongCSEM.out$CSEM$csem.strong, var_obs = strongCSEM.out$summary$value[3])# Sample of values csem_vals <- c(2.0, 2.5, 3.0) var_obs <- 25 stdCSEM(csem_vals, var_obs) #From Strong true score model library(psychTools) data(ability) data.ability <- ability[complete.cases(ability),] strongCSEM.out <- csemStrong(score.type = "dich", data = data.ability, nitems = 16, ci = TRUE, summary = TRUE) # Looking ouput strongCSEM.out # Standardized CSEM stdCSEM(csem = strongCSEM.out$CSEM$csem.strong, var_obs = strongCSEM.out$summary$value[3])