An sframe instrument records the research design, not
only the questions. This vignette builds a slice of the published
Thailand digital marketing study (Sharafuddin, Madhavan, and Wangtueai
2024) with the constructors shown one at a time, then adds the analysis
plan and a measurement model. The full study is assembled in the
worked-study vignette.
Choice sets define reusable response options. Items reference them
through choice_set.
Items are response variables unless their type is
section_break or text_block. Required items
carry required = TRUE. Item IDs should stay stable, because
response columns reuse them and the analysis plan refers to them. These
items measure perceived value (DMPV) and tourist satisfaction (TS).
intro <- sf_item(
"intro", "About your trip",
type = "section_break",
section_intro = "Please rate your experience of digital booking and your visit."
)
dmpv_1 <- sf_item("dmpv_1", "The destination's online content was trustworthy.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "DMPV")
dmpv_2 <- sf_item("dmpv_2", "The online information was consistent across platforms.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "DMPV")
dmpv_3 <- sf_item("dmpv_3", "The digital channels offered good value for money.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "DMPV")
dmpv_4 <- sf_item("dmpv_4", "I was aware of the destination through digital channels.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "DMPV")
ts_1 <- sf_item("ts_1", "The trip met my expectations.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "TS")
ts_2 <- sf_item("ts_2", "My overall travel experience was satisfying.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "TS")
ts_3 <- sf_item("ts_3", "I felt comfortable at the destination.",
type = "likert", required = TRUE, choice_set = "likert5", scale_id = "TS")
visitor_type <- sf_item("visitor_type", "I am a",
type = "single_choice", required = TRUE, choice_set = "visitor")
repeat_change <- sf_item(
"repeat_change", "What changed most since your previous visit?",
type = "textarea", required = FALSE
)
attention <- sf_item("attention", "For quality control, please select Agree.",
type = "single_choice", required = TRUE, choice_set = "likert5")A scale records item membership, the scoring method, any reverse-coded items, and the minimum number of valid items needed to compute a score.
Checks keep the quality-control logic with the instrument.
A branch shows or hides an item based on an earlier answer. Branch a dedicated follow-up, not an item from a shared scale, or groups may receive different versions of the scale being compared.
Each block binds a research question to a technique and to the
variables that fill each role. A reliability check expects
items. A group comparison expects a group and
an outcome.
analysis_plan <- list(
list(id = "M1", research_question = "Is perceived value internally consistent?",
family = "measurement", method = "reliability_alpha",
roles = list(items = c("dmpv_1", "dmpv_2", "dmpv_3", "dmpv_4"))),
list(id = "RQ1", research_question = "Do repeat visitors report higher satisfaction?",
family = "group_comparison", method = "mann_whitney",
roles = list(group = "visitor_type", outcome = "TS"),
options = list(alpha = 0.05))
)sf_instrument() takes the questions through
components and the research design through
analysis_plan and models. The model is added
with add_model(), which checks each indicator against the
instrument items.
instr <- sf_instrument(
title = "Digital marketing study (teaching slice)",
version = "1.0.0",
description = "A slice of the published Thailand study for teaching the constructors.",
authors = "Research team",
languages = "en",
components = list(
likert5, visitor,
intro, dmpv_1, dmpv_2, dmpv_3, dmpv_4, ts_1, ts_2, ts_3,
visitor_type, repeat_change, attention, dmpv, ts, attention_check,
repeat_branch
),
analysis_plan = analysis_plan
)
ts_model <- sf_model(
id = "ts_cfa",
label = "Satisfaction measurement model",
type = "cfa",
constructs = list(
sf_construct("DMPV", "Perceived value", c("dmpv_1", "dmpv_2", "dmpv_3", "dmpv_4")),
sf_construct("TS", "Tourist satisfaction", c("ts_1", "ts_2", "ts_3"))
)
)
instr <- add_model(instr, ts_model)validate_sframe() returns a diagnostic. Print it to read
the result, and use the accessors to get at the parts.
validate_sframe(instr, strict = FALSE)
#> <sframe validation>
#> Instrument: Digital marketing study (teaching slice) (1.0.0)
#> Status: valid
#> Checks: 29 run, 0 with problemsvalidation <- validate_sframe(instr, strict = FALSE)
sf_is_valid(validation)
#> [1] TRUE
sf_problems(validation)
#> character(0)In production, strict validation stops with a structured error when
anything is wrong. When it passes, as_sframe() recovers the
instrument with its validated stamp set.
An instrument rests on published work: the source of each scale, and
the method behind each plan block. sf_reference() records a
work as CSL-JSON, the format Zotero, Mendeley and pandoc share, and
cited_by says where the instrument cites it:
"instrument" as a whole, or "item:<id>",
"scale:<id>", "plan:<block id>" or
"model:<id>".
cronbach <- sf_reference(
id = "cronbach_1951",
title = "Coefficient alpha and the internal structure of tests",
author = "Cronbach, L. J.", year = 1951,
container = "Psychometrika", volume = "16", issue = "3", pages = "297-334",
cited_by = "plan:M1"
)A reference copied from Google Scholar, Zotero or a journal page
arrives as BibTeX, and read_bibtex() reads it with base R
alone.
likert <- read_bibtex(text = "@article{likert_1932,
author = {Likert, Rensis},
title = {A technique for the measurement of attitudes},
journal = {Archives of Psychology},
year = {1932}, volume = {22}, number = {140}, pages = {1--55}
}", cited_by = "instrument")
instr <- add_references(instr, cronbach, likert)
names(sframe_references(instr))
#> [1] "cronbach_1951" "likert_1932"
names(sframe_references(instr, cited_by = "plan:M1"))
#> [1] "cronbach_1951"validate_sframe() checks that every key is unique and
that each cited_by target exists. The references travel
inside the .sframe file. Citing a source is disclosure,
outside the design, so the content hash that amend_sframe()
records leaves references out, and a source can be added to
a published instrument directly.
render_report() cites each work in text, as author and
year, and lists every work once, in a References section at the end.
That list holds the instrument’s own references and the references of
every method the plan ran, formatted by pandoc in APA 7th edition, which
ships with the package, or in any Citation Style Language file given as
csl =. A written interpretation can cite a work as
[@key], and references = adds works cited
there. render_results() lists its references once at the
end in the same way. In SurveyBuilder, the References tab of Survey
settings takes pasted BibTeX or a typed reference, and SurveyStudio has
a References screen that does the same.
.sframe filesThe .sframe file is the portable instrument file. It
keeps the validated metadata, the analysis plan, and the model in one
place.
path <- tempfile(fileext = ".sframe")
write_sframe(instr, path, overwrite = TRUE)
loaded <- read_sframe(path)
inherits(loaded, "sframe")
#> [1] TRUE
sf_meta(loaded)$title
#> [1] "Digital marketing study (teaching slice)"
length(sf_plan(loaded))
#> [1] 2
length(loaded$models)
#> [1] 1
length(sframe_references(loaded))
#> [1] 2