Skip to contents

Schema and parameters from Shin and Park (2024) — multiple-baseline across three participants, fraction multiplication word problems via a tablet math application, two question types per session, counts correct (0-5). See web_based_data.csv at OSF F9832.

Data

library(scdbayes)

make_case <- function(case_id, n_a, baseline_acc, gain) {
  n_b <- 24 - n_a
  qt  <- rep(c("visualization", "solving"), each = 24)
  ses <- rep(seq_len(24), times = 2)
  ph  <- rep(c(rep("A", n_a), rep("B", n_b)), times = 2)
  outcome <- pmax(0L, pmin(5L, round(
    baseline_acc + gain * as.integer(ph == "B") + rnorm(length(ph), 0, 0.6)
  )))
  data.frame(case = case_id, time = ses, question_type = qt,
             phase = ph, outcome = outcome)
}

fractions <- rbind(
  make_case("C1",  6, 1.4, 2.8),
  make_case("C2",  9, 1.0, 3.0),
  make_case("C3", 12, 1.6, 2.4)
)
head(fractions, 4)
#>   case time question_type phase outcome
#> 1   C1    1 visualization     A       2
#> 2   C1    2 visualization     A       1
#> 3   C1    3 visualization     A       1
#> 4   C1    4 visualization     A       1

Columns

scdbayes uses your columns by name — there is no detection step to run. This dataset has case (participant), phase ("A" baseline, "B" treatment), time (session), outcome, and question_type (a within-case nesting variable). Pass these names directly to the functions below.

Design type and hierarchy

detect_design_type(fractions)
#> [1] "multiple_baseline"
detect_hierarchy_levels(fractions)[c("structure", "n_level1", "n_level2")]
#> $structure
#> [1] "two_level"
#> 
#> $n_level1
#> [1] 144
#> 
#> $n_level2
#> [1] 3

Phase (piecewise) coding

fractions_p <- process_scd_phases(fractions, structure = list(),
                                  scd_type = "multiple_baseline")
head(fractions_p[, c("case", "time", "phase", "level_AB",
                     "time_A", "trend_AB", "outcome")], 4)
#> # A tibble: 4 × 7
#>   case   time phase level_AB time_A trend_AB outcome
#>   <chr> <int> <chr>    <int>  <dbl>    <dbl>   <dbl>
#> 1 C1        1 A            0      0        0       2
#> 2 C1        1 A            0      0        0       1
#> 3 C2        1 A            0      0        0       1
#> 4 C2        1 A            0      0        0       2

Per-case descriptive features

compute_case_features(fractions)[, c("case", "mean_A", "mean_B",
                                     "NAP", "PND",
                                     "autocor_A", "autocor_B")]
#>        case    mean_A   mean_B       NAP       PND  autocor_A  autocor_B
#> times    C1 1.4166667 4.194444 0.9965278 0.9166667  0.2279116 -0.1201936
#> times1   C2 0.7777778 3.933333 1.0000000 1.0000000 -0.5225694 -0.2565826
#> times2   C3 1.7500000 3.875000 0.9817708 0.7083333  0.3273810  0.1750000

Phase descriptives

summarize_phase_descriptives(fractions_p, phase_var = "phase",
                             outcome_var = "outcome")[c("raw_difference",
                                                        "phase_a_mean",
                                                        "phase_b_mean")]
#> $raw_difference
#> [1] 2.67037
#> 
#> $phase_a_mean
#> [1] 1.351852
#> 
#> $phase_b_mean
#> [1] 4.022222

Random-effects structure

build_default_random_effects(fractions_p, scd_type = "ab",
                             case_var = "case",
                             nest_var = "question_type")
#> [1] "(1 + level_AB | case) + (1 + level_AB | case:question_type)"

Priors

adaptive <- generate_adaptive_priors(fractions_p, structure = list(),
                                     model_type = "gaussian")
adaptive$intercept$description
#> [1] "student_t(3, 3.02, 1.48)"
adaptive$treatment$description
#> [1] "normal(0, 0.74)"
adaptive$recommendations$overall
#> [1] "Prior strength: moderate (scale factor: 1.00)"

Fitting the Bayesian model

opts <- list(
  formula = outcome ~ time_A + level_AB + trend_AB +
                      (level_AB | case/question_type),
  family  = "cumulative",
  prior_type = "default",
  intervention_goal = "increase"
)
if (interactive()) {
  result <- run_scd_analysis(fractions_p, options = opts)
  result$diagnostics$converged
  summarize_fixed_effect_decisions(result$model)
}

Per-case decisions

The app’s Per Case tab reports each case’s own posterior (population term plus case-level deviation) for every coefficient that varies by case. The same table comes from summarize_per_case_effects().

if (interactive()) {
  summarize_per_case_effects(result$model,
                             intervention_goal = "increase")
}

Source study

  • Shin, M., & Park, J. (2024). Technology-assisted instruction with teacher prompts on fraction multiplication word problems: A single-case design with visual analysis and Bayesian multilevel modeling. Assistive Technology. https://doi.org/10.1080/10400435.2024.2415366