| Title: | Bayesian Q Methodology: Exact Rank-Order Likelihood for Forced Q Sorts |
|---|---|
| Description: | A Bayesian analysis for Q methodology, alongside the classical one. Models the forced Q sort as an ordered partition of the statements through an exact rank-order likelihood (the design quotas fix the partition margins, so the likelihood of the observed sorting event is exact), fits it by a parameter-expanded Gibbs sampler in R with no compiled code and a convergence gate on rotation-invariant functionals, resolves rotational ambiguity via the MatchAlign post-processing of Poworoznek et al. (2025) <doi:10.1214/25-BA1544>, and returns the familiar Q tables as posterior summaries: credible intervals for bounded participant loadings, flag probabilities with an explicit unclassified state, quota-respecting factor arrays, distinguishing and consensus statements judged against a posterior critical difference and a grid-width equivalence region, one posterior false-discovery rule for all published claims, and a two-signal posterior-predictive workflow for the number of factors. |
| Authors: | Raymond Dacosta Azadda [aut, cre] (ORCID: <https://orcid.org/0009-0002-4384-4556>), Henry Ofoe Agbi-Kaiser [aut] (ORCID: <https://orcid.org/0009-0008-6127-9136>), Hannah D. Robinson [aut] (ORCID: <https://orcid.org/0009-0000-5159-1363>), KyungSook Lee [aut] (ORCID: <https://orcid.org/0000-0003-2351-7355>), AK-ACE Team [aut], Karsten Hueffer [aut], Taa'aii Peter [aut], Stacy Rasmus [aut] |
| Maintainer: | Raymond Dacosta Azadda <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.2.0 |
| Built: | 2026-10-08 02:21:42 UTC |
| Source: | https://github.com/rdazadda/bayesqm |
assess_recovery() compares a point estimate and optional posterior
draws to a known loading truth, returning RMSE, per-factor RMSE,
bias, Tucker's congruence, credible-interval coverage, width, and
Gneiting-Raftery interval score. assess_classification() compares
a logical flag matrix to the true factor assignments using optimal
permutation matching.
assess_recovery(Lambda_hat, Lambda_true, Lambda_draws = NULL, prob = 0.95) assess_classification(flags, Lambda_true)assess_recovery(Lambda_hat, Lambda_true, Lambda_draws = NULL, prob = 0.95) assess_classification(flags, Lambda_true)
Lambda_hat |
Estimated loading matrix (N x K). |
Lambda_true |
True loading matrix. |
Lambda_draws |
Optional array of shape |
prob |
Credible-interval probability. |
flags |
Logical matrix of factor assignments. |
assess_recovery() returns a list of metrics;
assess_classification() returns a list with accuracy and
per_factor.
Every plot in the package reads its palette through
bayesqm_colors(). Call bayesqm_set_colors() to switch the active
scheme for every subsequent plot. The available built-in schemes are
"sorts" (default, the plot_sorts() colour family), "blue",
"teal", "red", "purple", and "grey".
For full control, pass a named list with slots dark, accent,
grey, gridgrey, and fill.
bayesqm_colors() bayesqm_set_colors(scheme)bayesqm_colors() bayesqm_set_colors(scheme)
scheme |
Character name of a built-in scheme, or a named list of colours with the slot names listed in the description. |
bayesqm_colors() returns the active palette as a named
list. bayesqm_set_colors() returns the previous scheme name,
invisibly.
bayesqm_colors() old <- bayesqm_set_colors("teal") bayesqm_colors()[["fill"]] bayesqm_set_colors(old)bayesqm_colors() old <- bayesqm_set_colors("teal") bayesqm_colors()[["fill"]] bayesqm_set_colors(old)
A single string naming the model, the panel, the draws, and the gate verdict — the provenance a figure caption should carry.
caption_bayesqm(fit, include_gate = TRUE)caption_bayesqm(fit, include_gate = TRUE)
fit |
A |
include_gate |
Append the gate report (default |
A length-one character string.
caption_bayesqm(demo_fit())caption_bayesqm(demo_fit())
Three checks, each comparing the observed sorts with replicates drawn
from the fitted model:
the agreement check (T1a) compares the observed person-agreement matrix
with replicated ones against a double-replicate reference; the
extra-factor check (T1b) locates the observed (K+1)-th eigenvalue in
its replicated distribution; and the paired-comparison check (T2)
compares standardized statement-pair margins, ties counted one half.
These are diagnostics to read, not tests to pass.
check_fit(fit, draws = 100)check_fit(fit, draws = 100)
fit |
A |
draws |
Posterior draws used for replication (default 100). |
A bayesqm_checks list: agreement (p), extra_factor
(percentile), and paired (p, per-statement p_j), with a print
method.
check_fit(demo_fit(), draws = 20)check_fit(demo_fit(), draws = 20)
For each participant, the model-agreement statistic m (mean over
draws of the best absolute Spearman agreement with any factor array)
and the person-agreement statistic w (best absolute agreement with
any other sort), each located against bands from mixed replicates
(fresh persons drawn from the fitted model). Verdicts: fits,
no_shared (below the model band, inside the person band),
unspanned (below the model band but above the person band, a shared
viewpoint the fitted factors do not span), and atypical. Unspanned
persons name their nearest partner.
check_persons(fit, draws = 60, mixes = 150)check_persons(fit, draws = 60, mixes = 150)
fit |
A |
draws |
Draw grid for the arrays (default 60). |
mixes |
Mixed replicates for the bands (default 150). |
A bayesqm_persons data frame: participant, m, w,
partner, verdict, with the band limits attached as attributes.
check_persons(demo_fit(), draws = 20, mixes = 40)check_persons(demo_fit(), draws = 20, mixes = 40)
Selects every claim — participant flags, distinguishing listings,
consensus statements, and pairwise stars — by the one posterior
false-discovery rule at level q, and reports the expected number of
false claims per family alongside. The same code path produces the
selected columns of compute_flags() and compute_qdc(), so the
tables and this object always agree.
claims(fit, q = 0.05, flag_floor = 0.5, cons_floor = 0.95)claims(fit, q = 0.05, flag_floor = 0.5, cons_floor = 0.95)
fit |
A |
q |
Posterior expected false-discovery bound (default 0.05). |
flag_floor, cons_floor
|
Selection floors for flags (0.5) and consensus statements (0.95). |
A bayesqm_claims object: selected-only tables flags,
distinguishing, consensus, and stars, each with its
expected_false count, plus the level q.
claims(demo_fit())claims(demo_fit())
Posterior-mean bounded loadings
## S3 method for class 'bayesqm_fit' coef(object, ...)## S3 method for class 'bayesqm_fit' coef(object, ...)
object |
A |
... |
Unused. |
An N x K matrix of posterior-mean bounded loadings (the
correlation-scale loading of the accompanying paper).
The reported array for each factor: statements sorted onto the design grid by their posterior column probabilities (mean grid column, tie-broken by posterior-mean score), which is quota-exact by construction. When the clue package is installed, a footrule assignment cross-check is computed and its disagreement rate attached.
compute_factor_array(fit, negative = FALSE)compute_factor_array(fit, negative = FALSE)
fit |
A |
negative |
Also return the negative-pole arrays (default |
A data frame with one row per statement: statement, then
f{k}_grid per factor (and f{k}_grid_neg when negative = TRUE).
attr(, "footrule_disagreement") gives the share of cells where the
footrule assignment differs (NA without clue).
compute_factor_array(demo_fit())compute_factor_array(demo_fit())
For each participant, the posterior probability that the classical flag
rule fires on each signed factor, with the probability of remaining
unclassified alongside. Selected flags come from all signed
candidates by the posterior false-discovery rule at level q.
compute_flags(fit, q = 0.05, floor = 0.5)compute_flags(fit, q = 0.05, floor = 0.5)
fit |
A |
q |
Posterior expected false-discovery bound (default 0.05). |
floor |
Minimum flag probability a candidate needs before it can be selected (default 0.5, so at most one signed flag per participant). |
A data frame with one row per participant: modal signed
candidate (factor, sign), its probability flag_prob,
unclassified_prob, and selected. The full probability matrix is
attached as attr(, "phi") and the expected number of false
selected flags as attr(, "expected_false").
compute_flags(demo_fit())compute_flags(demo_fit())
The correlation-scale loading of the accompanying paper,
rho = (S lambda)_k / sqrt(s^2 + 1), summarized per participant and
factor, with the posterior-mean person spread s_i alongside.
compute_loadings(fit, prob = NULL)compute_loadings(fit, prob = NULL)
fit |
A |
prob |
Credible-interval probability; defaults to the fit's. |
A data frame with one row per participant: participant, then
f{k}_loading, f{k}_lower, f{k}_upper per factor, then spread
(posterior-mean s_i).
compute_loadings(demo_fit())compute_loadings(demo_fit())
The statement verdict table. Distinguishing-for-a-factor is the joint
event that every contrast touching that factor exceeds the posterior
critical difference delta_kl (computed from the posterior spread of
the score contrasts); consensus is the equivalence event that all
scores sit within one grid column (delta_grid()) of each other. Both
families are selected through the posterior false-discovery rule, and a
statement can be distinguishing, consensus, or indeterminate.
compute_qdc(fit, q = 0.05, cons_floor = 0.95, prob = NULL)compute_qdc(fit, q = 0.05, cons_floor = 0.95, prob = NULL)
fit |
A |
q |
Posterior expected false-discovery bound (default 0.05). |
cons_floor |
Minimum consensus probability before a statement can be selected as consensus (default 0.95). |
prob |
Credible-interval probability for the contrast intervals; defaults to the fit's. The critical difference itself keeps its z_0.975 definition regardless. |
A data frame with one row per statement: per-factor
distinguishing probabilities, consensus_prob, and the verdict.
Attributes: delta_kl and delta_kl99 (per pair), delta_grid,
contrasts (the per-pair contrast table with intervals, the
probability diff_column_prob that the two viewpoints place the
statement in different grid columns, and stars, * for selected
claims and ** for those that also clear the z_0.995 critical
difference at probability .99), and expected_false per family.
compute_qdc(demo_fit())compute_qdc(demo_fit())
Statement scores with credible intervals
compute_zscores(fit, prob = NULL)compute_zscores(fit, prob = NULL)
fit |
A |
prob |
Credible-interval probability; defaults to the fit's. |
A data frame with one row per statement: statement, then
f{k}_zsc, f{k}_lower, f{k}_upper per factor.
compute_zscores(demo_fit())compute_zscores(demo_fit())
The crib sheet: for each statement and factor, the posterior probability of landing in the top or bottom grid column of that factor's array, and of carrying the highest or lowest score across factors.
crib_sheet(fit)crib_sheet(fit)
fit |
A |
A long data frame: statement, factor, p_top, p_bottom,
p_highest, p_lowest.
head(crib_sheet(demo_fit()))head(crib_sheet(demo_fit()))
The width of one grid column on the standardized score scale,
1 / sd(forced positions) with the population standard deviation. This
is the equivalence-region half-width used for consensus verdicts: a
score contrast smaller than one grid column is not expressible in a
completed sort.
delta_grid(distribution)delta_grid(distribution)
distribution |
Integer vector of forced-distribution counts (the number of statements allowed in each grid column). |
A single numeric value.
delta_grid(c(2, 3, 4, 5, 7, 7, 5, 4, 3, 2))delta_grid(c(2, 3, 4, 5, 7, 7, 5, 4, 3, 2))
Runs the partition-model sampler on a small synthetic forced-sort
dataset with a fixed seed and the convergence gate disabled. It exists
so examples and tests have a complete bayesqm_fit in about a second;
it is no substitute for fit_bayesian() at its defaults on real data.
demo_fit(N = 8, J = 13, K = 2, draws = 200, seed = 1)demo_fit(N = 8, J = 13, K = 2, draws = 200, seed = 1)
N, J, K
|
Panel size, statement count, factors (defaults 8, 13, 2). |
draws |
Kept posterior draws (default 200). |
seed |
Random seed (default 1). |
A bayesqm_fit.
fit <- demo_fit() fitfit <- demo_fit() fit
Warm-extends the fitted chain by further iterations and re-runs the convergence gate and the alignment on the grown draw set. The extension restores the sampler's saved random-number state, so the result is draw-for-draw identical to having run one longer chain, whatever happened in the session in between.
extend(fit, iterations = NULL, pivot = NULL, quiet = FALSE)extend(fit, iterations = NULL, pivot = NULL, quiet = FALSE)
fit |
A |
iterations |
Additional iterations; |
pivot, quiet
|
As in |
The extended bayesqm_fit.
The per-factor block of the accompanying paper: modal and mean number
of defining sorts per posterior draw with a credible interval, the
selected flag count, the mean posterior spread of the statement
scores, and the mean replicate reliability
R_i = s_i^2 / (1 + s_i^2) of the flagged participants. The
statement-score correlations between factors ride along as an
attribute.
factor_characteristics(fit, prob = 0.9, q = 0.05, floor = 0.5)factor_characteristics(fit, prob = 0.9, q = 0.05, floor = 0.5)
fit |
A |
prob |
Credible-interval probability for the defining-sort counts (default 0.90). |
q, floor
|
The flag rule fixing the flagged set, as in
|
A data frame with one row per factor: factor, flagged
(selected flags), defining_modal, defining_mean,
defining_lower, defining_upper, score_spread, and
reliability. Attribute score_correlations holds the posterior
mean K x K correlation matrix of the statement scores.
factor_characteristics(demo_fit())factor_characteristics(demo_fit())
Models each completed sort as a forced ordered partition of the
statements and samples the posterior of the latent factor model by a
parameter-expanded Gibbs sampler. Convergence is gated on
rotation-invariant person spreads (rank-normalized split-R-hat and
bulk/tail effective sample size); a chain failing the gate is
warm-extended at successive doublings up to max_iterations. Draws are
aligned by MatchAlign with a polarity canon, so defining sorts load
positively.
fit_bayesian( Y, K, iterations = 12000, burn = 2000, thin = 5, max_iterations = 48000, seed = NULL, sigma_scale = 1, rhat_max = 1.01, ess_min = 400, prob = 0.95, keep_raw = TRUE, pivot = NULL, quiet = FALSE, ... )fit_bayesian( Y, K, iterations = 12000, burn = 2000, thin = 5, max_iterations = 48000, seed = NULL, sigma_scale = 1, rhat_max = 1.01, ess_min = 400, prob = 0.95, keep_raw = TRUE, pivot = NULL, quiet = FALSE, ... )
Y |
A |
K |
Integer number of factors. |
iterations |
First-check chain length (default 12000, the settings frozen in the accompanying paper). |
burn |
Burn-in iterations (default 2000), paid once; extensions continue the chain. |
thin |
Keep every |
max_iterations |
Total-iteration cap for the gated extension ladder (default 48000). |
seed |
Optional integer seed; fits are exactly reproducible given the seed. |
sigma_scale |
Half-normal prior scale for the per-factor loading scales (default 1). |
rhat_max, ess_min
|
Gate thresholds (defaults 1.01 and 400). |
prob |
Credible-interval probability stored on the fit (default 0.95). |
keep_raw |
Keep the pre-alignment draws on the fit (default
|
pivot |
Optional draw index for the alignment pivot; |
quiet |
Suppress progress messages (default |
... |
Unused; supplying a removed 0.1.0 argument gives a migration error. |
A bayesqm_fit carrying aligned draws, the gate report, the
alignment record, and (when keep_raw = TRUE) the raw draws and
sampler state.
fit <- demo_fit() fitfit <- demo_fit() fit
Fits fit_bayesian() at each K in the ladder and stores, per rung, the
fit together with the adequacy and support evidence that
select_k() consumes. Expect roughly one full fit's runtime per rung;
a message up front says how many rungs are coming.
fit_ladder( Y, K_max = NULL, K_min = 2, q = 0.05, screen_draws = 30, screen_mixes = 60, quiet = FALSE, ... )fit_ladder( Y, K_max = NULL, K_min = 2, q = 0.05, screen_draws = 30, screen_mixes = 60, quiet = FALSE, ... )
Y |
As in |
K_max |
Largest K to fit. |
K_min |
Smallest K to fit (default 2). |
q |
False-discovery level for the support evidence stored on
each rung (default 0.05); |
screen_draws, screen_mixes
|
Budget for the per-rung person check (defaults 30 and 60; the cluster signal needs no more). |
quiet |
Suppress per-rung messages (default |
... |
Passed to |
A bayesqm_ladder: the per-rung fits and evidence.
Posterior-mean reconstruction on the utility scale
## S3 method for class 'bayesqm_fit' fitted(object, ...)## S3 method for class 'bayesqm_fit' fitted(object, ...)
object |
A |
... |
Unused. |
A J x N matrix of posterior-mean latent utilities
F Lambda'.
Reverses the sign of one factor's scores and loadings in every draw. The polarity canon orients factors so defining sorts load positively; this is the judgmental override.
flip_factor(fit, factor)flip_factor(fit, factor)
fit |
A |
factor |
Factor index or |
The fit with the factor's pole reversed.
generate_data() is the top-level data-generating function used
by the package's simulation studies and tests. It builds a
loading matrix (generate_loadings()), factor scores, noise of the
chosen type (generate_noise()), and discretises the continuous
signal onto a forced Q-sort grid (discretize_to_grid()). See also
get_distribution() for the standard forced-distribution lookup.
generate_data( N, J, K, noise_sd = 1, error_type = "normal", nu = 5, contam_prop = 0.1, contam_scale = 4, loading_type = "simple", primary_range = c(0.55, 0.85), cross_range = c(-0.15, 0.15), seed = NULL ) generate_loadings( N, K, primary_range = c(0.55, 0.85), cross_range = c(-0.15, 0.15), type = "simple" ) generate_noise( J, N, type = "normal", sd = 1, nu = 5, contam_prop = 0.1, contam_scale = 4 ) discretize_to_grid(Y_cont, distr) get_distribution(J)generate_data( N, J, K, noise_sd = 1, error_type = "normal", nu = 5, contam_prop = 0.1, contam_scale = 4, loading_type = "simple", primary_range = c(0.55, 0.85), cross_range = c(-0.15, 0.15), seed = NULL ) generate_loadings( N, K, primary_range = c(0.55, 0.85), cross_range = c(-0.15, 0.15), type = "simple" ) generate_noise( J, N, type = "normal", sd = 1, nu = 5, contam_prop = 0.1, contam_scale = 4 ) discretize_to_grid(Y_cont, distr) get_distribution(J)
N, J, K
|
Numbers of participants, statements, and factors. |
noise_sd |
Residual SD. |
error_type |
One of |
nu |
Degrees of freedom for |
contam_prop, contam_scale
|
Contamination rate and scale. |
loading_type |
|
primary_range, cross_range
|
Uniform ranges for primary and cross-loadings. |
seed |
Optional RNG seed; restored on exit. |
type |
For |
sd |
Residual SD for |
Y_cont |
Continuous scores (for |
distr |
Integer forced-distribution counts. |
generate_data() returns a list with Y, Lambda_true,
F_true, distribution, N, J, K. The component helpers
return their respective raw objects.
The grizzly bear reintroduction Q dataset from Easter et al. (2025): 67 participants each force-sorted 41 statements about reintroducing grizzly bears to the North Cascades onto an eleven-column grid (quotas 1-2-3-5-6-7-6-5-3-2-1, printed values -5 to +5). A real, published panel where the two-signal rule selects a two-factor solution, used in the package documentation.
grizzly_sortsgrizzly_sorts
A qsort_data object: the 41 x 67 integer matrix of printed grid values with statement and participant ids, and the forced distribution.
Easter, T. S., Santo, A. R., Sage, A. H., Carter, N. H., Chan, K. M. A., & Ransom, J. I. (2025). Divergent values and perspectives drive three distinct viewpoints on grizzly bear reintroduction in Washington, the United States. People and Nature, 7, 127–145. doi:10.1002/pan3.10748. Data from the Dryad repository under CC0, doi:10.5061/dryad.73n5tb369.
grizzly_sorts plot(grizzly_sorts, participants = 1:4)grizzly_sorts plot(grizzly_sorts, participants = 1:4)
Thin aliases that forward to read_pqmethod(), read_qsort() (HTMLQ
auto-detection), read_kenq(), and read_easyhtml_firebase(). These
exist only so scripts written against the qmethod package continue
to work; new code should call the read_* functions directly.
import.pqmethod(file, ...) import.htmlq(file, ...) import.kenq(file, ...) import.easyhtmlq(file, ...)import.pqmethod(file, ...) import.htmlq(file, ...) import.kenq(file, ...) import.easyhtmlq(file, ...)
file |
Path to the data file. |
... |
Passed to the underlying reader. |
A qsort_data object.
GHK-simulated log-likelihood of each participant's sort under each
kept posterior draw (thinned to draws), the input PSIS-LOO needs.
The GHK seed depends only on the draw index and the person, never on
K, so log-likelihoods are common-random-number comparable across a
ladder of fits.
loglik_person(fit, draws = 100, R = 64, seed = 1)loglik_person(fit, draws = 100, R = 64, seed = 1)
fit |
A |
draws |
Posterior draws to evaluate (default 100, thinned evenly). |
R |
GHK replications per evaluation (default 64). |
seed |
Base seed for the GHK draws (default 1). |
A draws x N matrix of log-likelihoods.
Person-level GHK log-likelihoods per rung, fed to PSIS-LOO. Reported as directional corroboration only: with typical Q panels (N well below 100), differences in expected log predictive density between adjacent K have unreliable standard errors. The GHK seeds are common across rungs, so comparisons are common-random-number paired.
loo_ladder(ladder, draws = 100, R = 64)loo_ladder(ladder, draws = 100, R = 64)
ladder |
A |
draws, R
|
As in |
A data frame: K, elpd_loo, se, max_pareto_k.
Resolves rotational, sign, and label-permutation ambiguity in posterior
draws by the MatchAlign procedure of Poworoznek et al. (2025), adapted to
the partition model: varimax rotation of the loadings per draw, a pivot
draw at the median condition number (overridable), pivot polarity fixed
so each factor's loadings skew positive (defining sorts load positively),
greedy signed matching of loading columns to the pivot, and a
Procrustes rotation. A final pass re-orients every draw to the varimax
of the aligned mean loadings, re-signed to positive skew, so the
delivered orientation does not inherit one draw's sampling noise. One
rotation is applied to loadings and scores alike, and the loading scale
sigma is carried through.
Called for its side effect on the draw arrays of an engine-level fit;
users normally receive already-aligned draws from fit_bayesian() and
need this only to realign under a different pivot.
matchalign(fit, pivot = NULL)matchalign(fit, pivot = NULL)
fit |
A fit carrying draw arrays |
pivot |
Optional draw index to use as the alignment pivot. |
The fit with aligned F, Lambda, and sigma, and the chosen
pivot index appended.
Poworoznek, E., Anceschi, N., Ferrari, F., & Dunson, D. (2025). Efficiently Resolving Rotational Ambiguity in Bayesian Matrix Sampling with Matching. Bayesian Analysis.
The childhood obesity Q dataset from Akhtar-Danesh (2023): 33 participants each force-sorted 42 statements about childhood obesity onto a nine-column grid (quotas 2-4-5-6-8-6-5-4-2, printed values -4 to +4). A real, published panel at typical Q scale, used in the package documentation.
obesity_sortsobesity_sorts
A qsort_data object: the 42 x 33 integer matrix of printed grid values with statement and participant ids, and the forced distribution.
Akhtar-Danesh, N. (2023). Impact of factor rotation on Q-methodology analysis. PLOS ONE, 18(9), e0290728. doi:10.1371/journal.pone.0290728
obesity_sorts plot(obesity_sorts, participants = 1:4)obesity_sorts plot(obesity_sorts, participants = 1:4)
The whole decision in one strip, one row per ladder rung. The left
span shows the adequacy signal, the extra-factor percentile inside
its shaded band, with a warning ring where the person check found a
mutual unspanned cluster. The right span shows one chip per factor,
coloured when the factor is supported and grey when not, with the
reason inside: f means fewer than two selected flags, d means no
selected distinguishing statement. Each row ends with its own verdict
in words, the selected row is boxed, and when no K passes both checks
the conclusion is written across the bottom of the plot.
plot_choice_k(x)plot_choice_k(x)
x |
A |
x, invisibly.
Per statement, the posterior contrast interval for one factor pair,
the posterior critical difference delta_kl (dashed), and the
grid-width consensus region (delta_grid(), shaded). Verdict
colours: selected distinguishing listings, consensus statements,
indeterminate.
plot_dist_cons(...) plot_contrasts(fit, pair = 1, q = 0.05, cons_floor = 0.95)plot_dist_cons(...) plot_contrasts(fit, pair = 1, q = 0.05, cons_floor = 0.95)
... |
Passed on. |
fit |
A |
pair |
Which factor pair to draw (index into the pair list or
|
q, cons_floor
|
As in |
fit, invisibly.
The reported array for one factor drawn as the physical sorting grid: columns are grid positions with their quota heights, each cell carries its statement, and cell shading shows how certain the placement is (the posterior probability of that statement landing in that column).
plot_factor_array(fit, factor = 1, labels = NULL)plot_factor_array(fit, factor = 1, labels = NULL)
fit |
A |
factor |
Which factor to draw (index or |
labels |
Optional statement labels (defaults to the statement ids). |
fit, invisibly.
One row per participant, one interval per factor on the bounded
loading scale, with selected flags marked. The dotted rules sit at
the classical descriptive cut-off 1.96 / sqrt(J) (reference).
plot_loading_posterior(fit, q = 0.05) ## S3 method for class 'bayesqm_fit' plot(x, ...)plot_loading_posterior(fit, q = 0.05) ## S3 method for class 'bayesqm_fit' plot(x, ...)
fit |
A |
q |
False-discovery level for the flag marks (default 0.05). |
x, ...
|
A |
fit, invisibly.
One row per participant, one dot per factor at its posterior flag probability (both poles combined; a minus sign marks a dominant negative pole), and a grey square for the probability of remaining unclassified. Filled dots are selected flags, and the dotted rule is the 0.5 selection floor.
plot_membership(...) plot_flags(fit, q = 0.05)plot_membership(...) plot_flags(fit, q = 0.05)
... |
Passed on. |
fit |
A |
q |
False-discovery level for the selection marks (default 0.05). |
fit, invisibly.
The m (model agreement) by w (person agreement) scatter with the
mixed-replication bands; verdict colours, and arrows from unspanned
persons to their nearest partners.
plot_person_check(x)plot_person_check(x)
x |
A |
x, invisibly.
The replicated distributions behind check_fit(): the agreement RMSE
against its double-replicate reference, and the observed extra-factor
eigenvalue in its replicated distribution.
plot_ppc(x)plot_ppc(x)
x |
A |
x, invisibly.
Draws each participant's completed sort as their own pyramid: one tile
per statement, stacked in its grid column, colored along the
disagree-agree axis. This is the look-at-the-decisions-first view:
run it straight after import, before any analysis, to see how every
participant grouped the statements. plot(qdata) does the same.
plot_sorts(x, participants = NULL, per_page = 12, labels = NULL, cex = NULL)plot_sorts(x, participants = NULL, per_page = 12, labels = NULL, cex = NULL)
x |
A |
participants |
Which participants to draw (names or indices);
|
per_page |
How many pyramids per page (default up to 12, arranged automatically); further participants continue on the next page. |
labels |
Optional statement labels for the tiles (defaults to the statement ids). |
cex |
Tile label size; |
The input, invisibly.
distr <- c(1, 2, 3, 2, 1) set.seed(1) Y <- replicate(4, { r <- integer(9) r[order(rnorm(9))] <- rep(seq_along(distr), distr) r - 3 # printed labels -2..+2 }) plot_sorts(qsort_data(Y, distribution = distr, validate = FALSE))distr <- c(1, 2, 3, 2, 1) set.seed(1) Y <- replicate(4, { r <- integer(9) r[order(rnorm(9))] <- rep(seq_along(distr), distr) r - 3 # printed labels -2..+2 }) plot_sorts(qsort_data(Y, distribution = distr, validate = FALSE))
The posterior of a single statement's score under each factor, drawn as full densities with the medians marked, plus the statement's verdict and its pairwise contrasts in the margin text. The drill-down for the statement a write-up centers on.
plot_statement(fit, statement, q = 0.05, cons_floor = 0.95) plot_zscore_posterior(...)plot_statement(fit, statement, q = 0.05, cons_floor = 0.95) plot_zscore_posterior(...)
fit |
A |
statement |
Statement id or index. |
q, cons_floor
|
As in |
... |
Passed on. |
fit, invisibly.
Traces of the invariant person spreads s_i for the persons with the
lowest effective sample size — the series the convergence gate reads —
plus the per-draw congruence of the aligned draws to the pivot, with
the gate report in the margin. A congruence histogram hugging 1 says
the alignment found one common orientation; a long left tail says some
draws sit far from it.
plot_tucker(...) plot_convergence(fit, n_series = 3)plot_tucker(...) plot_convergence(fit, n_series = 3)
... |
Passed on. |
fit |
A |
n_series |
How many worst-ESS persons to trace (default 3). |
fit, invisibly.
Every statement's score under every factor, with nested 50% and 95% credible intervals — the classic Q z-score chart carrying its uncertainty. Statements are ordered by how strongly the factors diverge on them, so the top of the chart is where the viewpoints disagree and the bottom is where they concur; the left margin marks each statement's verdict.
plot_zscores( fit, order_by = c("divergence", "score"), q = 0.05, cons_floor = 0.95 )plot_zscores( fit, order_by = c("divergence", "score"), q = 0.05, cons_floor = 0.95 )
fit |
A |
order_by |
|
q, cons_floor
|
As in |
fit, invisibly.
Generic for posterior credible intervals, defined here so the package needs no Stan-ecosystem dependency. Compatible with the generic of the same name in rstantools.
posterior_interval(object, ...)posterior_interval(object, ...)
object |
A fitted model object. |
... |
Passed to methods. |
See the method documentation.
Posterior credible intervals for any subset of parameters in a
bayesqm_fit. Method for posterior_interval().
## S3 method for class 'bayesqm_fit' posterior_interval(object, prob = 0.95, pars = NULL, regex_pars = NULL, ...)## S3 method for class 'bayesqm_fit' posterior_interval(object, prob = 0.95, pars = NULL, regex_pars = NULL, ...)
object |
A |
prob |
Coverage probability (default 0.95). |
pars |
Optional character vector of exact parameter names. |
regex_pars |
Optional regex; matching parameter names are included
in addition to those named in |
... |
Unused. |
A matrix with one row per parameter and two columns for the lower and upper interval bounds.
Generic for summarizing the priors a model was fit with, defined here so the package needs no Stan-ecosystem dependency. Compatible with the generic of the same name in rstantools.
prior_summary(object, ...)prior_summary(object, ...)
object |
A fitted model object. |
... |
Passed to methods. |
See the method documentation.
The partition model's priors, as a printable bayesqm_prior object.
Method for prior_summary().
## S3 method for class 'bayesqm_fit' prior_summary(object, ...)## S3 method for class 'bayesqm_fit' prior_summary(object, ...)
object |
A |
... |
Unused. |
A bayesqm_prior data frame with columns parameter and
prior.
qsort_data() is the canonical constructor for a Q-sort dataset.
validate_qsort(), check_distribution(), and infer_distribution()
are the validation helpers used internally by the constructor and
by the file readers. parse_distribution() accepts a numeric vector,
a comma-/semicolon-/space-separated string, or a text file containing
one of those.
qsort_data( Y, statements = NULL, participants = NULL, distribution = NULL, metadata = list(), source = "manual", validate = TRUE ) validate_qsort(qdata, distribution = NULL) check_distribution(Y, distribution) infer_distribution(Y) parse_distribution(x)qsort_data( Y, statements = NULL, participants = NULL, distribution = NULL, metadata = list(), source = "manual", validate = TRUE ) validate_qsort(qdata, distribution = NULL) check_distribution(Y, distribution) infer_distribution(Y) parse_distribution(x)
Y |
A |
statements, participants
|
Optional character vectors of IDs;
default to |
distribution |
Optional integer vector of forced-distribution
counts. Inferred from |
metadata |
Optional named list of study-level info. |
source |
Provenance string stored on the object. |
validate |
If |
qdata |
A |
x |
Numeric vector, character string, or path to a file
containing the forced distribution, passed to
|
qsort_data() returns a qsort_data S3 list with fields
Y, statements, participants, distribution, metadata, and
source. validate_qsort() returns a list with valid, issues,
warnings, and summary. check_distribution() returns a list
with ok, non_conforming, and grid_values.
infer_distribution() and parse_distribution() return integer
vectors.
Print, summary, and matrix conversion for qsort_data
## S3 method for class 'qsort_data' print(x, ...) ## S3 method for class 'qsort_data' summary(object, ...) ## S3 method for class 'qsort_data' as.matrix(x, ...)## S3 method for class 'qsort_data' print(x, ...) ## S3 method for class 'qsort_data' summary(object, ...) ## S3 method for class 'qsort_data' as.matrix(x, ...)
x, object
|
A |
... |
Unused. |
print() and summary() return the input invisibly;
as.matrix() returns the J x N Q-sort matrix.
read_qsort() auto-detects the file format from extension and content
and dispatches to a specialised reader. The specialised readers are
also exported for explicit use:
read_qsort_csv(), read_qsort_excel() for generic CSV / Excel
(with HTMLQ / FlashQ / Ken-Q auto-detection baked in)
read_pqmethod() for PQMethod .DAT files
read_kenq() for Ken-Q JSON or CSV
read_kenq_excel() for multi-sheet Ken-Q Excel (Type 1 and Type 2,
both old and Ver2 sub-formats)
read_kade_zip() for KADE ZIP archives
read_easyhtml_firebase() for Easy-HTMLQ Firebase JSON
read_statements() for a standalone statement-text file
All readers return a qsort_data object in J x N orientation
(statements as rows, participants as columns).
read_qsort(file, format = "auto", ...) read_qsort_csv( file, orientation = c("auto", "statements_rows", "participants_rows"), id_col = c("auto", "first", "none"), statements = NULL, distribution = NULL, ... ) read_qsort_excel( file, sheet = 1, orientation = c("auto", "statements_rows", "participants_rows"), id_col = c("auto", "first", "none"), statements = NULL, distribution = NULL, ... ) read_pqmethod(file, statements_file = NULL) read_kenq(file, format = c("auto", "json", "csv")) read_kenq_excel(file) read_kade_zip(file) read_easyhtml_firebase(file) read_statements(file, column = 1, id_column = NULL)read_qsort(file, format = "auto", ...) read_qsort_csv( file, orientation = c("auto", "statements_rows", "participants_rows"), id_col = c("auto", "first", "none"), statements = NULL, distribution = NULL, ... ) read_qsort_excel( file, sheet = 1, orientation = c("auto", "statements_rows", "participants_rows"), id_col = c("auto", "first", "none"), statements = NULL, distribution = NULL, ... ) read_pqmethod(file, statements_file = NULL) read_kenq(file, format = c("auto", "json", "csv")) read_kenq_excel(file) read_kade_zip(file) read_easyhtml_firebase(file) read_statements(file, column = 1, id_column = NULL)
file |
Path to the data file. |
format |
For |
... |
Passed to the underlying reader. |
orientation |
For generic CSV/Excel: |
id_col |
For generic CSV/Excel: |
statements, distribution
|
Optional overrides passed to
|
sheet |
Excel sheet name or index (default |
statements_file |
For PQMethod, optional separate statements file. |
column, id_column
|
For |
A qsort_data object, except read_statements() which
returns a named character vector.
Replaces the f1 ... fK labels with substantive names everywhere the
fit carries them, so every downstream table and plot uses the new
names.
rename_factors(fit, new_names)rename_factors(fit, new_names)
fit |
A |
new_names |
Character vector of length |
The renamed fit.
Judgmental rotation: each aligned draw's statement scores are rotated
toward an analyst-specified target by Procrustes, and the loadings
receive the same rotation (its inverse transpose when oblique = TRUE),
so the latent utilities every draw implies are unchanged. Summaries
computed from the returned fit are summaries of the rotated solution,
with full posterior uncertainty.
rotate_factors(fit, target, oblique = FALSE)rotate_factors(fit, target, oblique = FALSE)
fit |
A |
target |
A |
oblique |
Allow an oblique (non-orthogonal) rotation
(default |
The fit with rotated draws; fit$align$rotated records the
call.
Opens a graphics device chosen from the file extension (.pdf,
.svg, .png, .tiff, .jpeg), evaluates expr so whatever it
draws lands on that device, and closes the device. expr is lazily
evaluated, so a call like save_bayesqm_plot("fig.pdf", plot(fit))
does not draw to the current screen device first. If expr returns
a ggplot object (for example, from ggplot2::autoplot()), it is
print()ed onto the device.
save_bayesqm_plot(file, expr, width = 7.2, height = 5, dpi = 300)save_bayesqm_plot(file, expr, width = 7.2, height = 5, dpi = 300)
file |
Output path. Extension determines the device. |
expr |
Plotting expression (lazily evaluated). |
width, height
|
Dimensions in inches. Defaults to a 7.2 x 5 inch two-column journal figure. |
dpi |
Resolution for raster formats ( |
The file path, invisibly.
f <- file.path(tempdir(), "fig.pdf") save_bayesqm_plot(f, plot(1:10)) unlink(f)f <- file.path(tempdir(), "fig.pdf") save_bayesqm_plot(f, plot(1:10)) unlink(f)
Signal one is posterior-predictive adequacy: the extra-factor check sits inside the central band and the person check shows no mutual unspanned cluster. Signal two is parsimony: every factor is supported, meaning at least two selected flags and at least one selected distinguishing listing. The selection is the smallest adequate K with all factors supported. When no factor is supported at any rung the verdict separates two opposite situations: a panel sharing nothing (no factor ever attracts two flags) and a panel so unanimous that flags abound but no statement distinguishes any pair — a single shared viewpoint, reported as such. When adequacy and support never coincide, both candidate solutions are reported rather than forcing a winner.
select_k(ladder, q = NULL, band = c(0.05, 0.95))select_k(ladder, q = NULL, band = c(0.05, 0.95))
ladder |
A |
q |
Re-select the support evidence at this level; |
band |
Central adequacy band for the extra-factor percentile
(default |
A bayesqm_selection with the verdict, the per-rung evidence
table, and the selected K (or NA).
Posterior-mean loading scales
## S3 method for class 'bayesqm_fit' sigma(object, ...)## S3 method for class 'bayesqm_fit' sigma(object, ...)
object |
A |
... |
Unused. |
Named numeric vector of posterior-mean sigma_k.
Linear-algebra utilities shared by MatchAlign and the recovery
assessments. tucker_congruence(x, y) computes sum(x*y) / sqrt(sum(x^2) * sum(y^2)). procrustes_rotation(X, Target) finds
the orthogonal R minimising ||X R - Target||_F and returns
X %*% R with R attached as attribute "rotation".
tucker_congruence(x, y) procrustes_rotation(X, Target)tucker_congruence(x, y) procrustes_rotation(X, Target)
x, y
|
Numeric vectors (for Tucker). |
X, Target
|
Matrices (for Procrustes). |
Tucker returns a scalar; Procrustes returns the rotated
matrix with a "rotation" attribute.