surveyframe 0.4.0 is on CRAN
surveyframe, CRAN, R package, MCDA, AHP, TOPSIS, text analysis, topic modelling, provenance, small samples
TL;DR: surveyframe 0.4.0 reached CRAN on 20 August 2026. Install it with install.packages("surveyframe"). This is the largest release so far. It adds multi-criteria decision analysis with 10 methods, a 9-method text-analysis family for open-ended responses, a track of small-sample corrections and a disclosed-amendment and Git-linked provenance trail for .sframe files. It also carries 2 breaking changes, described at the end. Free and open source under the MIT licence.
Decision analysis, collected inside the instrument
Multi-criteria decision analysis usually sits in a gap. Computation packages assume a clean decision matrix already exists. Survey software stops at the questionnaire. Getting from one to the other is manual work, and mistakes enter there.
0.4.0 closes that gap. It ships 10 methods, each carrying a verified literature citation:
- The Analytic Hierarchy Process (AHP) and the Analytic Network Process (ANP)
- The Decision Making Trial and Evaluation Laboratory method (DEMATEL)
- VIKOR, MOORA, SMART, WASPAS, PROMETHEE, ELECTRE and TOPSIS
Two new item types collect the judgement data inside the survey itself. pairwise_comparison uses Saaty’s 1-to-9 ratio scale for AHP and ANP, or a 0-to-4 directed influence scale for DEMATEL. criteria_weight is a constant-sum allocation across criteria. Both render identically in the static HTML survey, the Shiny module and the builder preview.
An aggregation layer turns per-respondent answers into the matrices the methods consume. It validates that every pair was answered, and it combines respondents with the geometric mean for AHP and ANP, which preserves reciprocity, or the arithmetic mean for DEMATEL. AHP judgements are screened for consistency against Saaty’s random-index table, and the consistency-ratio distribution is reported for every study, with or without a filtering threshold declared in advance.
Every ranking method resolves its inputs in the same order, and records where each number came from, so a results table can state the provenance of what it shows. sensitivity_analysis() reports how far a ranking moves under a declared perturbation of the weights, and carries a degenerate flag, so a ranking whose alternatives were tied from the start reports that tie in place of stability.
Each method’s implementation had to agree with an independent computation of the same method on the same matrix before it was accepted. That practice caught a real defect during development, a WASPAS runner that had inherited SMART’s normalisation step by mistake.
Text analysis for open-ended responses
Open-ended answers are usually the part of a survey left unanalysed. 0.4.0 adds a 9-method family for them, running through the same analysis-plan and reporting pipeline as every other method:
term_freqandngram_freq, top terms and top bigrams or trigrams, as a bar chart or word cloudterm_context, a keyword-in-context concordance showing what came before and after a chosen wordco_occurrenceandco_occurrence_network, pairwise co-occurrence as a heatmap and a clustered force-directed networktidy_sentiment, positive and negative counts and the proportion positivequanteda_dfm, a document-feature matrix summarytopic_model_ldaandstm_topics, Latent Dirichlet Allocation and structural topic modelling
A shared cleaning step, clean_text_responses(), and a 174-word English stopword list are both exported, so a study can reuse or override them outside a runner. The heavier methods keep their dependencies optional.
The vignette lists what the family leaves out: stemming, lemmatisation, tf-idf and keyness comparison.
Corrections for small samples
Applied research usually runs on fewer respondents than the textbook assumes, and the ordinary versions of these tests can flip significance on repeated draws from data whose true difference stayed the same. This release adds:
- The Hodges-Lehmann shift estimator, for the two-group Mann-Whitney comparison
- The paired Wilcoxon pseudomedian confidence interval, for the paired t-test
- The exact odds-ratio confidence interval on Fisher’s test, which avoids the continuity correction a Wald interval needs when a cell is zero
- Firth’s bias-reduced logistic regression, for regression prone to separation at small n
An advisory on assumption_report() and sample_size_plan() flags when a study’s sample size falls in the range where these are worth considering.
Disclosed amendments and a provenance trail
A SHA-256 hash proves a .sframe file is unchanged since it was written. A legitimate revision and an undisclosed edit break the hash identically, so the hash alone treats them the same.
0.4.0 adds a disclosed-revision path alongside the hash check, which keeps its full strength. amend_sframe() compares an instrument before and after a change and appends a timestamped entry to an ordered log, keeping every earlier entry. Each entry records a reason from a controlled vocabulary, a free-text explanation and which top-level fields changed.
Amendments come in 2 tiers. Pipeline amendments, such as a data correction or bot-response removal, need only a reason. Design amendments, meaning anything touching the analysis plan or a model, require a deviation report describing what changed in the research question, method or model and why. The sign-off field is always filled. It records a reviewer’s name or the literal none, so an unreviewed design change stays visible to anyone auditing the file.
link_git_commit() records the current Git commit SHA and subject line alongside an instrument, tying the file hash to a commit that already has an explanation attached. Git is optional.
An edit made directly to a .sframe file, bypassing amend_sframe(), still fails the integrity check on read exactly as it did before.
The .sframe format is now documented as a standalone JSON Schema, so a reviewer or a second tool can validate a file with the schema alone.
What breaks
Two changes need attention before you upgrade.
validate_sframe() and validate_model() now return an sframe_validation diagnostic object, visibly, whatever the value of strict. Reading $valid and $problems still works, so the common pattern needs no migration. What breaks is code using the return value as an instrument, as in instrument <- validate_sframe(instrument). Wrap it in as_sframe(). Passing a validation result where an instrument is expected now raises an error that names the fix.
The Shiny collector now emits one expansion column per matrix cell, where it used to pipe-join a matrix item’s cells into a single column.
Both changes came out of a code review by a Journal of Statistical Software editor. The same review prompted accessor methods for every class, so user code works through methods and leaves the underlying list alone. The registered S3 method count went from 41 to 103.
Get it
- Install:
install.packages("surveyframe") - Documentation: mohammedalisharafuddin.github.io/surveyframe
- Source: github.com/MohammedAliSharafuddin/surveyframe
- On CRAN: CRAN.R-project.org/package=surveyframe
The follow-up release, 0.4.1, adds a 22-demo teaching library and labelled SPSS and Stata export.