The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Building a survey instrument: questions, plan, and model

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

Choice sets define reusable response options. Items reference them through choice_set.

likert5 <- sf_choices(
  "likert5",
  values = 1:5,
  labels = c("Strongly disagree", "Disagree",
             "Neither agree nor disagree", "Agree", "Strongly agree")
)

visitor <- sf_choices("visitor", c("first_time", "repeat"),
                      c("First-time visitor", "Repeat visitor"))

Items and item types

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")

attention <- sf_item("attention", "For quality control, please select Agree.",
  type = "single_choice", required = TRUE, choice_set = "likert5")

Scales, reverse coding, and minimum valid items

A scale records item membership, the scoring method, any reverse-coded items, and the minimum number of valid items needed to compute a score.

dmpv <- sf_scale("DMPV", "Digital marketing perceived value",
  items = c("dmpv_1", "dmpv_2", "dmpv_3", "dmpv_4"), method = "mean", min_valid = 3)

ts <- sf_scale("TS", "Tourist satisfaction",
  items = c("ts_1", "ts_2", "ts_3"), method = "mean", min_valid = 2)

Attention checks

Checks keep the quality-control logic with the instrument.

attention_check <- sf_check(
  id = "attention_agree", item_id = "attention", type = "attention",
  pass_values = 4, fail_action = "flag", label = "Instructional attention check"
)

Branching

A branch shows or hides an item based on an earlier answer. This one is a placeholder for a repeat-visitor follow-up.

repeat_branch <- sf_branch(
  item_id    = "ts_3",
  depends_on = "visitor_type",
  operator   = "==",
  value      = "repeat",
  action     = "show"
)

The analysis plan

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))
)

Assemble the instrument

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, 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 the instrument

validation <- validate_sframe(instr, strict = FALSE)
validation$valid
#> [1] TRUE
validation$problems
#> character(0)

In production, strict validation returns the validated instrument or stops with a structured error.

instr <- validate_sframe(instr)
instr$meta$validated
#> [1] TRUE

Write and read .sframe files

The .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
loaded$meta$title
#> [1] "Digital marketing study (teaching slice)"
length(loaded$analysis_plan)
#> [1] 2
length(loaded$models)
#> [1] 1

GUI option

The same instrument, plan, and model can be authored in SurveyBuilder, which saves a .sframe file for use in R.

launch_builder()
launch_builder_demo(open = FALSE)

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.