Cookbook: Ordinal Outcome, End to End

One complete, runnable script for an ordinal outcome — ordered categories such as a 4-point severity scale or a Likert response. Same four steps as every cookbook (see vignette("cookbook-continuous")). Responses are recorded as integer levels 1, 2, …, K; the default estimand is the treatment coefficient of a proportional-odds (cumulative logit) model, and the InferenceOrdinal* family also offers adjacent- category, continuation-ratio, probit, cauchit and cloglog links plus matched-design (KK) variants.

Setup

EDI is not on CRAN yet, so install.packages("EDI") fails — install from R-universe (fallback: GitHub, subdir = "R/EDI"). Not evaluated here.

install.packages("EDI", repos = c("https://kapelner.r-universe.dev", "https://cloud.r-project.org"))
# or: remotes::install_github("kapelner/EDI", subdir = "R/EDI")
library(EDI)
set.seed(20260916)

n = 100
X = data.frame(
  baseline_score = round(rnorm(n, 5, 1.5), 1),
  female         = rbinom(n, 1, 0.5)
)
true_effect = 0.8   # shift on the latent logistic scale

Fixed design, proportional odds

Outcomes are drawn from a latent-variable model: a linear predictor plus logistic noise, cut at three thresholds into four ordered levels.

des = DesignFixedBernoulli$new(n = n, response_type = "ordinal", verbose = FALSE)
des$add_all_subjects_to_experiment(X)
des$assign_w_to_all_subjects()
w = des$get_w()

eta = true_effect * w + 0.3 * (X$baseline_score - 5) - 0.2 * X$female
u   = runif(n)
y   = ifelse(u <= plogis(-1.0 - eta), 1L,
      ifelse(u <= plogis( 0.2 - eta), 2L,
      ifelse(u <= plogis( 1.1 - eta), 3L, 4L)))
des$add_all_subject_responses(y)
table(level = y, treatment = w)
#>      treatment
#> level  0  1
#>     1 23  5
#>     2 18  7
#>     3 10  7
#>     4  8 22

inf = InferenceOrdinalPropOddsRegr$new(des, verbose = FALSE)
inf$num_cores = 1L
inf$compute_estimate()                         # treatment log-odds shift
#> [1] 1.812752
inf$compute_asymp_confidence_interval(alpha = 0.05)
#>     2.5%    97.5% 
#> 1.009556 2.615949
inf$compute_asymp_two_sided_pval()
#> [1] 9.711939e-06
inf$set_seed(1)
inf$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
#> [1] 0.01
inf$set_seed(1)
inf$compute_bootstrap_confidence_interval(alpha = 0.05, B = 200, show_progress = FALSE)
#>  2.5% 97.5% 
#>    NA    NA

Everything at once

suite = InferenceSuite$new(des)
res = suite$run_all_inference(screen = TRUE, plots = FALSE, num_cores = 1L,
                              methods = c("wald", "score", "lik_ratio"), max_secs_per_class = 15)
#> inference       cov      estimand    est       se        pval       pval method     status 
#> class           mod                                                                        
#> ===========================================================================================
#> Classes 0/28  [                0%                 ] Status: Estimating...Avg Δ                    mean Δ      1.07      0.220     5.27e-06   wald            ok     
#> Classes 1/28  [=              3%                ] Estimated Time Left: 0sAvg Δ Pooled …           mean Δ      1.07      0.219     3.78e-06   wald            ok     
#> Classes 2/28  [==             7%                ] Estimated Time Left: 0sWilcox                   HL shift    1.00      0.255     1.16e-05   wald            ok     
#> Classes 3/28  [===            10%               ] Estimated Time Left: 0sAdj Cat Logit…  ~.       logodds a…  0.913     0.216     2.38e-05   wald            ok     
#> Classes 4/28  [====           14%               ] Estimated Time Left: 0sAdj Cat Logit…  ~.       logodds a…  0.913     0.216     5.63e-06   score           ok     
#> Classes 5/28  [=====          17%               ] Estimated Time Left: 0sAdj Cat Logit…  ~.       logodds a…  0.913     0.216     2.83e-06   lik_ratio       ok     
#> Classes 6/28  [=======        21%               ] Estimated Time Left: 0sCauchit Regr    ~.       cauchit l…  1.60      0.465     5.74e-04   wald            ok     
#> Classes 7/28  [========       25%               ] Estimated Time Left: 0sCauchit Regr    ~.       cauchit l…  1.60      0.465     1.52e-05   score           ok     
#> Classes 8/28  [=========      28%               ] Estimated Time Left: 0sCauchit Regr    ~.       cauchit l…  1.60      0.465     1.81e-05   lik_ratio       ok     
#> Classes 9/28  [==========     32%               ] Estimated Time Left: 0sCloglog Regr    ~.       cloglog l…  1.22      0.280     1.27e-05   wald            ok     
#> Classes 10/28 [===========    35%               ] Estimated Time Left: 0sCloglog Regr    ~.       cloglog l…  1.22      0.280     4.31e-06   score           ok     
#> Classes 11/28 [============   39%               ] Estimated Time Left: 0sCloglog Regr    ~.       cloglog l…  1.22      0.280     3.16e-06   lik_ratio       ok     
#> Classes 12/28 [============== 42%               ] Estimated Time Left: 0sCont Ratio Re…  ~.       logodds c…  1.49      0.337     9.54e-06   wald            ok     
#> Classes 13/28 [============== 46%               ] Estimated Time Left: 0sCont Ratio Re…  ~.       logodds c…  1.49      0.337     4.48e-06   score           ok     
#> Classes 14/28 [============== 50%               ] Estimated Time Left: 0sCont Ratio Re…  ~.       logodds c…  1.49      0.337     2.89e-06   lik_ratio       ok     
#> Classes 15/28 [============== 53%               ] Estimated Time Left: 0sG Comp Avg Δ    ~.       mean Δ      1.07      0.213     4.90e-07   wald            ok     
#> Classes 16/28 [============== 57%               ] Estimated Time Left: 0sJonckheere Te…           stoch ord…  0.250     0.0590    2.31e-05   wald            ok     
#> Classes 17/28 [============== 60% =             ] Estimated Time Left: 0sOrdered Probi…  ~.       probit or…  1.10      0.238     3.66e-06   wald            ok     
#> Classes 18/28 [============== 64% ==            ] Estimated Time Left: 0sOrdered Probi…  ~.       probit or…  1.10      0.238     3.65e-06   score           ok     
#> Classes 19/28 [============== 67% ===           ] Estimated Time Left: 0sOrdered Probi…  ~.       probit or…  1.10      0.238     3.05e-06   lik_ratio       ok     
#> Classes 20/28 [============== 71% ====          ] Estimated Time Left: 0sPartial Propo…  ~.       logodds p…  1.81      0.410     2.50e-05   wald            ok     
#> Classes 21/28 [============== 75% =====         ] Estimated Time Left: 0sProp Odds Regr  ~.       logodds p…  1.81      0.410     9.71e-06   wald            ok     
#> Classes 22/28 [============== 78% ======        ] Estimated Time Left: 0sProp Odds Regr  ~.       logodds p…  1.81      0.410     4.87e-06   score           ok     
#> Classes 23/28 [============== 82% ========      ] Estimated Time Left: 0sProp Odds Regr  ~.       logodds p…  1.81      0.410     3.83e-06   lik_ratio       ok     
#> Classes 24/28 [============== 85% =========     ] Estimated Time Left: 0sRidit                    mann whit…  0.250     0.0397    3.04e-10   wald            ok     
#> Classes 25/28 [============== 89% ==========    ] Estimated Time Left: 0sStereotype Lo…  ~.       stereotyp…  2.54      0.643     8.00e-05   wald            ok     
#> Classes 26/28 [============== 92% ===========   ] Estimated Time Left: 0sStereotype Lo…  ~.       stereotyp…  2.54      0.643     4.95e-06   score           ok     
#> Classes 27/28 [============== 96% ============  ] Estimated Time Left: 0sStereotype Lo…  ~.       stereotyp…  2.54      0.643     3.33e-06   lik_ratio       ok     
#> Classes 28/28 [============= 100% ==============] Estimated Time Left: 0s-------------------------------------------------------------------------------------------
#> Status: Completed in 1s.
#> 
#>   Estimand: cauchit link effect (3 inferences)   : p = 0.000138
#>   Estimand: cloglog link effect (3 inferences)   : p = 0.000100
#>   Estimand: HL shift (1 inferences)              : p =       NA
#>   Estimand: logodds adj cat (3 inferences)       : p = 0.000100
#>   Estimand: logodds cont ratio (3 inferences)    : p = 0.000100
#>   Estimand: logodds partial prop (1 inferences)  : p =       NA
#>   Estimand: logodds prop (3 inferences)          : p = 0.000100
#>   Estimand: mann whitney effect (1 inferences)   : p =       NA
#>   Estimand: mean Δ (3 inferences)                : p = 0.000100
#>   Estimand: probit ordinal (3 inferences)        : p = 0.000100
#>   Estimand: stereotype link effect (3 inferences): p = 0.000100
#>   Estimand: stoch ordering trend (1 inferences)  : p =       NA
#> 
#> Combined evidence against the sharp null across 12 estimands
#> (28 inferences, weighting = uniform within estimand):
#> p = 0.000102

Sequential design

des_seq = DesignSeqOneByOneKK14$new(n = n, response_type = "ordinal", verbose = FALSE)
for (i in seq_len(n)) {
  w_i   = des_seq$add_one_subject_to_experiment_and_assign(X[i, , drop = FALSE])
  eta_i = true_effect * w_i + 0.3 * (X$baseline_score[i] - 5) - 0.2 * X$female[i]
  u_i   = runif(1)
  y_i   = if (u_i <= plogis(-1.0 - eta_i)) 1L else if (u_i <= plogis(0.2 - eta_i)) 2L else
          if (u_i <= plogis(1.1 - eta_i)) 3L else 4L
  des_seq$add_one_subject_response(i, y_i)
}

inf_seq = InferenceOrdinalPropOddsRegr$new(des_seq, verbose = FALSE)
inf_seq$num_cores = 1L
inf_seq$compute_estimate()
#> [1] 0.4983639
inf_seq$set_seed(1)
inf_seq$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
#> [1] 0.2

Where to go next

mirror server hosted at Truenetwork, Russian Federation.