Skip to contents

Computes marginal means (MMs) or average marginal component effects (AMCEs) with correction for intra-respondent reliability (IRR, \(\tau\)). When a repeated task is present, IRR is estimated unless a fixed value is supplied. Results are returned in a structured object ready for plotting and summary.

Usage

projoint(
  .data,
  .qoi = NULL,
  .by_var = NULL,
  .structure = "choice_level",
  .estimand = "mm",
  .se_method = "analytical",
  .irr = NULL,
  .remove_ties = TRUE,
  .ignore_position = NULL,
  .n_sims = NULL,
  .n_boot = NULL,
  .weights_1 = NULL,
  .clusters_1 = NULL,
  .se_type_1 = NULL,
  .weights_2 = NULL,
  .clusters_2 = NULL,
  .se_type_2 = NULL,
  .auto_cluster = TRUE,
  .seed = NULL
)

Arguments

.data

A projoint_data created by reshape_projoint or make_projoint_data.

.qoi

Optional projoint_qoi describing the quantity of interest. If supplied, its fields override .structure and .estimand.

.by_var

Optional column name (character) for subgroup analysis; must be logical (TRUE/FALSE) or numeric/integer coded as 0/1. Only supported for .structure == "profile_level" (ignored otherwise).

.structure

Either "profile_level" or "choice_level" (default "choice_level"). Overridden by .qoi$structure if present.

.estimand

Either "mm" (marginal mean) or "amce" (average marginal component effect). Default "mm". Overridden by .qoi$estimand if present.

.se_method

Standard-error method: "analytical" (default), "simulation", or "bootstrap".

.irr

Numeric or NULL. If NULL (default), IRR is estimated (when design allows); otherwise a fixed IRR value is used and IRR estimation is skipped.

.remove_ties

Logical; remove ties in choice data before estimation? Default TRUE.

.ignore_position

Logical; choice-level only. Ignore profile position (left/right)? Default TRUE.

.n_sims

Integer; required when .se_method = "simulation".

.n_boot

Integer; required when .se_method = "bootstrap".

.weights_1, .clusters_1, .se_type_1

Passed to lm_robust when estimating IRR.

.weights_2, .clusters_2, .se_type_2

Passed to lm_robust when estimating MMs/AMCEs.

.auto_cluster

Logical. If TRUE (default), automatically cluster on an id column when present and no .clusters_* are supplied. Auto-clustering only occurs when the corresponding .se_type_* is NULL.

.seed

Optional integer. Sets a temporary RNG seed for reproducible simulation/bootstrap inside the call; restores the previous RNG state on exit.

Value

A projoint_results object (list-like) with components such as:

  • $estimand, $structure, $se_method, $irr, $tau

  • $labels: attribute/level mapping used in estimation

  • $estimates: a data frame of estimates with columns like att_level_choose, att_level_notchoose (if choice-level), estimate, se / std.error, conf.low, conf.high, and an estimand label such as "mm_corrected" or "amce_uncorrected".

This object is suitable for downstream use in plot.projoint_results, summary.projoint_results, and related helpers.

Details

Most users will pass a projoint_data object (from reshape_projoint or make_projoint_data). Advanced users may specify custom quantities via projoint_qoi; if provided, its structure and estimand override .structure and .estimand.

Valid se_type_* values depend on clustering:

  • Without clusters: "classical", "HC0", "HC1", "HC2", "HC3"

  • With clusters: "CR0", "CR1", "CR2", "stata", "none"

If NULL, estimatr defaults are used (HC2 when unclustered; CR2 when clustered).

Examples

# \donttest{
# Prepare example data
data(exampleData1)
outcomes <- c(paste0("choice", 1:8), "choice1_repeated_flipped")
pj <- reshape_projoint(exampleData1, outcomes)

# Choice-level QoI based on pj$labels
att <- unique(pj$labels$attribute_id)[1]
lev_ids   <- pj$labels$level_id[pj$labels$attribute_id == att]
lev_names <- sub(".*:", "", lev_ids)

q <- set_qoi(
    .structure     = "choice_level",
    .estimand      = "mm",
    .att_choose    = att,
    .lev_choose    = lev_names[2],
    .att_notchoose = att,
    .lev_notchoose = lev_names[1]
  )
  
# Choice-level, marginal means (fast example: fix IRR)
fit_choice <- projoint(
  pj,
  .qoi = q,
  .structure = "choice_level",
  .estimand  = "mm",
  .irr       = 0.80,        # skip IRR estimation for a quick example
  .se_method = "analytical"
)
head(summary(fit_choice))
#> 
#> Summary of Projoint Estimates
#> ------------------------------
#> Estimand: mm
#> Structure: choice_level
#> Standard error method: analytical
#> SE type (lm_robust):   CR2 (clustered by id)
#> IRR: Assumed (0.8)
#> Tau: 0.113
#> 
#> # A tibble: 2 × 7
#>   estimand       estimate     se conf.low conf.high att_level_choose
#>   <chr>             <dbl>  <dbl>    <dbl>     <dbl> <chr>           
#> 1 mm_uncorrected    0.432 0.0195    0.394     0.471 att1:level2     
#> 2 mm_corrected      0.413 0.0251    0.363     0.462 att1:level2     
#> # ℹ 1 more variable: att_level_notchoose <chr>

# Profile-level AMCEs
fit_profile <- projoint(
  pj,
  .structure = "profile_level",
  .estimand  = "amce",
  .se_method = "analytical"
)
#> Warning: AMCE analytical SEs: CR2 produced non-PSD/NA variances; fell back to se_type='stata' (then HC1 if needed).
#> Warning: AMCE analytical SEs: CR2 produced non-PSD/NA variances; fell back to se_type='stata' (then HC1 if needed).
#> Warning: AMCE analytical SEs: CR2 produced non-PSD/NA variances; fell back to se_type='stata' (then HC1 if needed).
#> Warning: AMCE analytical SEs: CR2 produced non-PSD/NA variances; fell back to se_type='stata' (then HC1 if needed).
# Plot using the S3 plot method
p <- plot(fit_profile, .estimates = "both")
print(p)

# }