Type: Package
Title: Conjoint Analysis with Reliability Correction and Visualization
Version: 1.0.6
Date: 2025-10-24
Maintainer: Yusaku Horiuchi <yusaku.horiuchi@gmail.com>
Author: Yusaku Horiuchi ORCID iD [aut, cre], Aaron Kaufman ORCID iD [aut], Gary King ORCID iD [aut]
Description: Provides tools for analyzing data generated from conjoint survey experiments, a method widely used in the social sciences for studying multidimensional preferences. The package implements estimation of marginal means (MMs) and average marginal component effects (AMCEs), with corrections for measurement error. Methods include profile-level and choice-level estimators, bias correction using intra-respondent reliability (IRR), and visualization utilities. For details on the methodology, see Clayton, Horiuchi, Kaufman, King, and Komisarchik (2025) https://gking.harvard.edu/conjointE.
Imports: dplyr (≥ 1.1.2), readr, rlang, tidyr, stringr, tidyselect, estimatr, ggthemes, ggplot2, stats, tibble, methods, MASS, forcats, scales
Suggests: tidyverse, knitr, rmarkdown, downloadthis, patchwork, testthat (≥ 3.0.0), DiagrammeR
VignetteBuilder: knitr
License: MIT + file LICENSE
Encoding: UTF-8
RoxygenNote: 7.3.2
Config/testthat/edition: 3
URL: https://yhoriuchi.github.io/projoint/
Depends: R (≥ 4.1.0)
LazyData: false
BugReports: https://github.com/yhoriuchi/projoint/issues
NeedsCompilation: no
Packaged: 2025-10-24 22:41:21 UTC; yusakuhoriuchi
Repository: CRAN
Date/Publication: 2025-10-29 19:50:09 UTC

Projoint Example Data Set 1: Building Conjoint with a Repeated, Flipped Task

Description

A cleaned Qualtrics export from a conjoint study that compares two potential new building developments. Each respondent completed 8 standard tasks as well as a repeated version of the first task (flipped), which can be used to calculate intra-respondent reliability (response instability).

Usage

data(exampleData1)

Format

A data frame with 400 rows and 185 columns. Contains survey responses including demographic information, outcome choices, and conjoint attribute values identified by K-*-* variable names.

Examples

# Load the dataset
data(exampleData1)

# Inspect the first few rows
head(exampleData1)

# Number of rows and columns
dim(exampleData1)

# Display column names (truncated here)
names(exampleData1)[1:10]


Projoint Example Data Set 1: "Labelled Tibble"

Description

A cleaned tibble where each attribute corresponds to a separate column with a descriptive attribute name. The unit of observation is each of two profiles in each task for each respondent.

Usage

data(exampleData1_labelled_tibble)

Format

A tibble with 6,400 rows and 14 columns. Contains survey responses including outcome choices and conjoint attribute values (columns typically named with a 'K-*-*' convention).

Details

This dataset is intended for illustrating reading, reshaping, and analysis workflows in projoint. Column names are compatible with reshape_projoint().

Source

Qualtrics survey on Prolific; see Clayton et al. replication materials.

Examples

# Load the data
data(exampleData1_labelled_tibble)

# Basic inspection (fast and always runnable)
head(exampleData1_labelled_tibble)
dim(exampleData1_labelled_tibble)

# Optional: quick structure peek (names only)
names(exampleData1_labelled_tibble)


Projoint Example Data Set 2: Building Conjoint with a Repeated, Non-Flipped Task

Description

A cleaned Qualtrics export from a conjoint study that compares two potential new building developments. Each respondent completed 8 standard tasks as well as a repeated version of the first task, where the profiles were presented in the same left-right positions (not flipped).

Usage

data(exampleData2)

Format

A data frame with 400 rows and 185 columns. Contains survey responses including demographic information, outcome choices, and conjoint attribute values identified by K-*-* variable names.

Examples

# Load the dataset
data(exampleData2)

# Inspect the first few rows
head(exampleData2)

# Number of rows and columns
dim(exampleData2)

# Display first 10 column names
names(exampleData2)[1:10]


Projoint Example Data Set 3: Building Conjoint with No Repeated Task

Description

A cleaned Qualtrics export from a conjoint study that compares two potential new building developments. Each respondent completed 8 standard tasks only; no repeated tasks are included in this dataset.

Usage

data(exampleData3)

Format

A data frame with 400 rows and 184 columns. Contains survey responses including demographic information, outcome choices, and conjoint attribute values identified by K-*-* variable names.

Examples

# Load the dataset
data(exampleData3)

# Inspect the first few rows
head(exampleData3)

# Number of rows and columns
dim(exampleData3)

# Display first 10 column names
names(exampleData3)[1:10]


Make a projoint_data object from a labelled tibble

Description

Converts a labelled tibble/data frame (one column per attribute) into an object of class projoint_data that downstream functions (e.g., projoint) can consume. The unit of observation should be each of two profiles in each task for each respondent.

Usage

make_projoint_data(
  .dataframe,
  .attribute_vars,
  .id_var = "id",
  .task_var = "task",
  .profile_var = "profile",
  .selected_var = "selected",
  .selected_repeated_var = NULL,
  .fill = FALSE
)

Arguments

.dataframe

A data frame (or tibble). One row per profile per task per respondent.

.attribute_vars

Character vector of attribute column names.

.id_var

Column name (character) with respondent IDs. Default "id".

.task_var

Column name (character) with task numbers. Default "task".

.profile_var

Column name (character) with profile numbers. Default "profile".

.selected_var

Column name (character) with the binary choice for each task (values in {0,1}). Default "selected".

.selected_repeated_var

Optional column name (character) with the binary choice for the repeated task. Default NULL.

.fill

Logical. If TRUE, uses repeated-task agreement to fill missing agreement values for non-repeated tasks (assumes IRR is independent of table content). If unsure, prefer the default FALSE.

Value

A projoint_data object (a list-like object containing a labels tibble and a data tibble) ready to pass to projoint and related functions.

Examples


# Example: build a projoint_data object from the labelled-tibble example
data(exampleData1_labelled_tibble)

att_cols <- c("School Quality", "Violent Crime Rate (Vs National Rate)",
              "Racial Composition", "Housing Cost",
              "Presidential Vote (2020)", 
              "Total Daily Driving Time for Commuting and Errands",
              "Type of Place")

pj_dat <- make_projoint_data(
  .dataframe             = exampleData1_labelled_tibble,
  .attribute_vars        = att_cols,
  .id_var                = "id",
  .task_var              = "task",
  .profile_var           = "profile",
  .selected_var          = "selected",
  .selected_repeated_var = "selected_repeated",
  .fill                  = FALSE
)

class(pj_dat)
# [1] "projoint_data"


Organize data for estimation (internal helper)

Description

Prepares tidy inputs for MM/AMCE estimation and IRR handling. Called inside pj_estimate() after reshaping to respondent–task–profile.

Usage

organize_data(
  .dataframe,
  .structure,
  .estimand,
  .remove_ties,
  .att_choose,
  .lev_choose,
  .att_notchoose,
  .lev_notchoose
)

Arguments

.dataframe

A tibble/data frame from reshape_projoint(), containing columns like id, task, profile, selected, agree (if repeated), and attribute columns named att1, att2, ... that store level_ids (e.g., "att1:level2").

.structure

Either "profile_level" or "choice_level".

.estimand

Either "mm" or "amce".

.remove_ties

Logical; if TRUE (default) remove tied responses in profile-level setups (keeps tasks where exactly one profile is selected).

.att_choose

Attribute ID for the “chosen” side (e.g., "att3").

.lev_choose

Level ID(s) for the chosen side (e.g., "level2" for profile-level; vector of level IDs for choice-level).

.att_notchoose

Attribute ID for the “not chosen” side (choice-level only).

.lev_notchoose

Level ID(s) for the not-chosen side (choice-level only).

Value

A named list with two tibbles:


Example Output: Manually Rearranged Labels

Description

A toy projoint_data object showing what happens after labels have been manually rearranged (e.g., via save_labels / read_labels).

Usage

data(out1_arranged)

Format

An object of class projoint_data. Contains two elements:

Details

Useful for illustrating workflows without requiring users to re-run the reordering themselves.


Internal Estimation Function

Description

Core workhorse for computing marginal means (MMs) or AMCEs from a conjoint design, with optional intra-respondent reliability (IRR) correction.

Usage

pj_estimate(
  .data,
  .structure,
  .estimand,
  .att_choose,
  .lev_choose,
  .att_notchoose,
  .lev_notchoose,
  .att_choose_b,
  .lev_choose_b,
  .att_notchoose_b,
  .lev_notchoose_b,
  .se_method,
  .irr,
  .remove_ties,
  .ignore_position,
  .n_sims,
  .n_boot,
  .weights_1,
  .clusters_1,
  .se_type_1,
  .weights_2,
  .clusters_2,
  .se_type_2,
  .auto_cluster = TRUE,
  .seed = NULL
)

Arguments

.data

A projoint_data object created by reshape_projoint or make_projoint_data.

.structure

Either "profile_level" or "choice_level".

.estimand

Either "mm" (marginal mean) or "amce" (average marginal component effect).

.att_choose

Attribute for the chosen profile/feature.

.lev_choose

Level(s) for the chosen profile/feature. Length 1 for profile_level; may be 1+ for choice_level.

.att_notchoose

Attribute for the not-chosen profile/feature (required for choice_level).

.lev_notchoose

Level(s) for the not-chosen profile/feature (required for choice_level).

.att_choose_b

(AMCE only) Baseline attribute for comparison.

.lev_choose_b

(AMCE only) Baseline level(s) for comparison.

.att_notchoose_b

(AMCE only, choice-level only) Baseline attribute for the not-chosen profile.

.lev_notchoose_b

(AMCE only, choice-level only) Baseline level(s) for the not-chosen profile.

.se_method

One of "analytical", "simulation", or "bootstrap".

.irr

NULL (default) to estimate IRR from repeated tasks; otherwise a numeric IRR value.

.remove_ties

Logical; should ties be removed before estimation? Defaults to TRUE.

.ignore_position

Logical; only for choice_level. If TRUE (default), ignore profile position (left/right).

.n_sims

Integer; required if .se_method == "simulation".

.n_boot

Integer; required if .se_method == "bootstrap".

.weights_1

(Optional) Bare (unquoted) column with weights for IRR estimation; passed to lm_robust.

.clusters_1

(Optional) Bare (unquoted) column with clusters for IRR estimation; passed to lm_robust.

.se_type_1

SE type for IRR estimation; passed to lm_robust. If NULL, estimatr defaults are used (HC2 when unclustered; CR2 when clustered).

.weights_2

(Optional) Bare (unquoted) column with weights for MM/AMCE estimation; passed to lm_robust.

.clusters_2

(Optional) Bare (unquoted) column with clusters for MM/AMCE estimation; passed to lm_robust.

.se_type_2

SE type for MM/AMCE estimation; passed to lm_robust. If NULL, estimatr defaults are used (HC2 when unclustered; CR2 when clustered).

.auto_cluster

Logical; if TRUE (default), auto-cluster on id when present and no .clusters_* are supplied; auto-clustering only occurs when the corresponding .se_type_* is NULL. See projoint.

.seed

Optional integer. If supplied, sets a temporary RNG seed for reproducible simulation/bootstrap inside this call and restores the previous RNG state on exit.

Details

IRR is clipped to [0.5, 1) (with a tiny epsilon) to avoid boundary issues. For choice-level MMs, ties must be removed (.remove_ties = TRUE). When .seed is supplied, the previous RNG state is restored on exit.

Value

A data frame with rows for the requested estimand(s) and columns:

See Also

lm_robust, projoint, projoint_level, projoint_diff


Plot method for projoint_results

Description

Creates publication-ready plots from a projoint_results object produced by projoint. Supports both profile-level and choice-level analyses, with plotting options tailored to each structure.

Usage

## S3 method for class 'projoint_results'
plot(
  x,
  .estimates = "corrected",
  .by_var = FALSE,
  .labels = NULL,
  .base_size = 12,
  .base_family = "",
  .type = c("bar", "pointrange"),
  .show_attribute = TRUE,
  .remove_xaxis = FALSE,
  .xlim = c(0, 1),
  .plot.margin = c(0, 3, 0, 3),
  ...
)

Arguments

x

A projoint_results object (typically from projoint).

.estimates

Character: which estimates to plot. One of "corrected", "uncorrected", or "both" (for profile-level), and "corrected" or "uncorrected" (for choice-level). Default "corrected".

.by_var

Logical (profile-level only). Whether to plot subgroup differences. Default FALSE.

.labels

Character vector of length 2 (choice-level only). Custom x-axis labels for bar/pointrange plots. If NULL, labels are taken from x$labels.

.base_size

Numeric. Base font size. Default 12.

.base_family

Character. Base font family. Default "" (system default).

.type

Character (choice-level only). One of "bar" or "pointrange". Default "bar".

.show_attribute

Logical (choice-level only). Show the attribute name as the title when both levels belong to the same attribute. Default TRUE.

.remove_xaxis

Logical (choice-level only). Remove x-axis line, ticks, and labels. Default FALSE.

.xlim

Numeric length-2 vector (choice-level only). X-axis limits. Default c(0, 1).

.plot.margin

Numeric length-4 vector (choice-level only). Plot margins in cm: c(top, left, bottom, right). Default c(0, 3, 0, 3).

...

Additional arguments passed to downstream plotting helpers.

Details

For profile-level results, only .by_var, .base_size, and .base_family are relevant. For choice-level results, only .type, .labels, .show_attribute, .remove_xaxis, .xlim, and .plot.margin are relevant. Irrelevant arguments are ignored with a warning.

Value

A ggplot2 object.

See Also

projoint, plot_projoint_profile_level, plot_projoint_choice_level_mm

Examples


data(exampleData1)

# Two base tasks (1 & 2) + repeated of task 1 (last)
dat <- reshape_projoint(
  exampleData1,
  .outcomes = c("choice1", "choice2", "choice1_repeated_flipped")
)

# Build a valid QOI from the labels
att <- unique(dat$labels$attribute_id)[1]
levs <- subset(dat$labels, attribute_id == att)$level_id
lev_names <- sub(".*:", "", levs)

q <- set_qoi(
  .structure     = "choice_level",
  .estimand      = "mm",
  .att_choose    = att,
  .lev_choose    = lev_names[2],
  .att_notchoose = att,
  .lev_notchoose = lev_names[1]
)

fit <- projoint(dat, .qoi = q)

# Plot method
plot(fit)


Plot method for projoint_tau

Description

Visualizes the estimated intra-respondent reliability (\tau) produced by the extrapolation method and stored in a projoint_tau object.

Usage

## S3 method for class 'projoint_tau'
plot(x, ...)

Arguments

x

A projoint_tau object.

...

Optional arguments (currently unused).

Value

A ggplot2 object representing the IRR (\tau) visualization. The plot is drawn for its side effect and also returned (invisibly).

Examples


# Estimate tau, then plot:
# dat <- reshape_projoint(exampleData1, .outcomes = c("choice1","choice2"))
# tau_fit <- projoint_tau(dat)  # or predict_tau(dat)
# p <- plot(tau_fit)            # also returns the ggplot object (invisibly)


Plot choice-level marginal means (MMs) (helper)

Description

Internal helper used by plot.projoint_results to render choice-level marginal means (MMs). Supports a bar chart or a horizontal pointrange layout and optional custom level labels.

Usage

plot_projoint_choice_level_mm(
  x,
  .type = "pointrange",
  .estimates = "corrected",
  .labels = NULL,
  .show_attribute = TRUE,
  .remove_xaxis = FALSE,
  .xlim = c(0, 1),
  .plot.margin = c(top = 1, left = 2, bottom = 1, right = 2),
  ...
)

Arguments

x

A projoint_results object produced by projoint with structure = "choice_level" and estimand = "mm".

.type

Character. Either "bar" (two bars with CIs) or "pointrange" (horizontal estimate with CI and level labels at the extremes). Default "pointrange".

.estimates

Character. Which estimate version to plot: "corrected" (default) or "uncorrected".

.labels

Optional character vector of length 2 for custom level labels (left/right). If NULL, labels are derived from x$labels.

.show_attribute

Logical; if TRUE (default), add the attribute name as the title when both levels are from the same attribute.

.remove_xaxis

Logical; if TRUE, remove x-axis line, ticks, and labels (useful when embedding). Default FALSE.

.xlim

Numeric length-2 giving the x-axis limits. Default c(0, 1).

.plot.margin

Numeric vector of plot margins in cm, c(top, left, bottom, right). Default c(1, 2, 1, 2).

...

Currently unused (reserved for future extensions).

Details

This helper expects that the projoint_results object already contains a single pair of choice-level MMs (i.e., one att_level_choose and one att_level_notchoose). It is called internally by plot.projoint_results when x$structure == "choice_level" and x$estimand == "mm".

When .type = "pointrange", the level labels are placed just outside .xlim to avoid overlap with the confidence interval. If the two levels correspond to different attributes, the attribute title is omitted and a message is emitted.

Value

A ggplot2 object.

See Also

plot.projoint_results for the user-facing plot method.

Examples

data(exampleData1)
dat <- reshape_projoint(exampleData1,
  .outcomes = c("choice1", "choice2", "choice1_repeated_flipped")
)
att <- unique(dat$labels$attribute_id)[1]
levs <- subset(dat$labels, attribute_id == att)$level_id
lev_names <- sub(".*:", "", levs)
q <- set_qoi("choice_level", "mm",
  .att_choose = att, .lev_choose = lev_names[2],
  .att_notchoose = att, .lev_notchoose = lev_names[1]
)
fit <- projoint(dat, .qoi = q)
plot(fit)

Estimate intra-respondent reliability (tau) without a repeated task

Description

Uses the extrapolation method to estimate intra-respondent reliability (IRR, \tau) when your conjoint design does not include an explicit repeated task. The input is a projoint_data object (e.g., produced by reshape_projoint).

Usage

predict_tau(.data, .title = NULL)

Arguments

.data

A projoint_data object (from reshape_projoint).

.title

Optional character string used as the plot title prefix.

Details

The procedure constructs pairs of base tasks within respondent, computes the proportion of identical choices as a function of how many attributes differ between the two tasks, fits a weighted regression of agreement on the number of differing attributes, and extrapolates to zero differences to obtain \hat{\tau}.

Value

A projoint_tau object (list-like) with components:

See Also

plot.projoint_tau, summary.projoint_tau, reshape_projoint

Examples


# Example workflow:
data(exampleData1)
outcomes <- c(paste0("choice", 1:8), "choice1_repeated_flipped")

# Even if your real study lacks a repeated task, this shows the API:
pj <- reshape_projoint(exampleData1, outcomes, .repeated = TRUE)

tau_fit <- predict_tau(pj, .title = "IRR (tau): ")
# Inspect the extrapolated tau (row where x == 0)
tau_fit$irr[tau_fit$irr$x == 0, ]

# Plot (also available via plot(tau_fit))
print(tau_fit$figure)



Print a projoint_data object

Description

Custom print method for objects of class projoint_data.

Usage

## S3 method for class 'projoint_data'
print(x, ...)

Arguments

x

A projoint_data object.

...

Additional arguments (currently unused).

Value

No return value, called for its side effect of printing a summary of the projoint_data object to the console.

Examples


data(exampleData1)
dat <- reshape_projoint(
  exampleData1,
  .outcomes = c("choice1", "choice2")
)
print(dat)


Print method for projoint_results

Description

Custom print method for objects of class projoint_results.

Usage

## S3 method for class 'projoint_results'
print(x, ...)

Arguments

x

An object of class projoint_results.

...

Additional arguments (ignored).

Value

No return value, called for its side effect of printing a summary of the projoint_results object to the console.

Examples


data(exampleData1)
dat <- reshape_projoint(
  exampleData1,
  .outcomes = c("choice1", "choice2", "choice1_repeated_flipped")
)
att <- unique(dat$labels$attribute_id)[1]
levs <- subset(dat$labels, attribute_id == att)$level_id
lev_names <- sub(".*:", "", levs)
q <- set_qoi(
  .structure     = "choice_level",
  .estimand      = "mm",
  .att_choose    = att,
  .lev_choose    = lev_names[2],
  .att_notchoose = att,
  .lev_notchoose = lev_names[1]
)
fit <- projoint(dat, .qoi = q)
print(fit)


Print method for projoint_tau objects

Description

Custom print method for objects of class projoint_tau, typically created by projoint or related functions.

Usage

## S3 method for class 'projoint_tau'
print(x, ...)

Arguments

x

An object of class projoint_tau.

...

Additional arguments (currently unused).

Value

No return value; called for its side effect of printing a summary of the estimated intra-respondent reliability (\tau).

Examples

toy_tau <- structure(
  list(irr = data.frame(predicted = 0.413, se = 0.02, n = 200)),
  class = "projoint_tau"
)
print(toy_tau)

Analyze a conjoint dataset with measurement-error correction

Description

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.

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:

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

Value

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

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

See Also

reshape_projoint, projoint_qoi, plot.projoint_results, summary.projoint_results

Examples


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

# Profile-level AMCEs
fit_profile <- projoint(
  pj,
  .structure = "profile_level",
  .estimand  = "amce",
  .se_method = "analytical"
)
# Plot using the S3 plot method
p <- plot(fit_profile, .estimates = "both")
print(p)



Create a projoint_data Object

Description

Internal constructor for projoint_data objects. Used by reshape_projoint and make_projoint_data to bundle conjoint survey labels and response data into a consistent structure.

Usage

projoint_data(labels, data)

Arguments

labels

A data frame of conjoint attribute–level metadata. Must include attribute names, attribute IDs (e.g., "att1"), and level IDs (e.g., "att1:lev1").

data

A data frame (typically a tibble) containing the reshaped conjoint survey responses, one row per respondent–task–profile, with attribute columns, selected, agree, and any covariates.

Value

A list of length two with class "projoint_data", containing:


Estimate subgroup differences (internal)

Description

Worker used by projoint to compute subgroup differences (group == 1 minus group == 0) in marginal means (MMs) or average marginal component effects (AMCEs). Supported only for .structure = "profile_level".

Usage

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

Arguments

.data

A projoint_data object.

.qoi

Optional projoint_qoi; if NULL, estimates all MMs/AMCEs.

.by_var

Column name in .data$data defining subgroups; must be logical, numeric/integer coded as 0/1, or factor with levels "0"/"1".

.structure

Must be "profile_level".

.estimand

Either "mm" or "amce".

.se_method

One of "analytical", "simulation", or "bootstrap".

.irr

NULL to estimate IRR from repeated tasks, or numeric to fix IRR.

.remove_ties

Logical; drop ties before estimation? Default TRUE.

.ignore_position

Ignored (subgroup analysis is profile-level only).

.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 for IRR estimation.

.weights_2, .clusters_2, .se_type_2

Passed to lm_robust for MM/AMCE estimation.

.auto_cluster

Logical; if TRUE (default), auto-cluster on id when suitable and no clusters are provided (applies only if the corresponding .se_type_* is NULL).

.seed

Optional integer; sets a temporary RNG seed and restores prior state on exit.

Value

A projoint_results object containing subgroup differences with fields:

See Also

projoint, projoint_level, projoint_results


Estimate profile- or choice-level effects (internal)

Description

Core worker used by projoint to compute marginal means (MMs) or average marginal component effects (AMCEs) under either the profile- or choice-level structure. Handles IRR usage (estimated or fixed) and the requested standard-error method.

Usage

projoint_level(
  .data,
  .qoi,
  .structure,
  .estimand,
  .se_method,
  .irr,
  .remove_ties,
  .ignore_position,
  .n_sims,
  .n_boot,
  .weights_1,
  .clusters_1,
  .se_type_1,
  .weights_2,
  .clusters_2,
  .se_type_2,
  .auto_cluster = TRUE,
  .seed = NULL
)

Arguments

.data

A projoint_data object.

.qoi

Optional projoint_qoi; if NULL, estimates all MMs/AMCEs implied by the design. When supplied, overrides .structure and .estimand.

.structure

Either "profile_level" or "choice_level".

.estimand

Either "mm" (marginal mean) or "amce" (average marginal component effect).

.se_method

One of "analytical", "simulation", or "bootstrap".

.irr

NULL to estimate IRR from repeated tasks; numeric to fix IRR.

.remove_ties

Logical; whether to drop tied responses (default TRUE).

.ignore_position

Logical; choice-level only. Ignore left/right position? 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

Arguments passed to lm_robust for IRR estimation. If .se_type_1 is NULL, estimatr defaults are used.

.weights_2, .clusters_2, .se_type_2

Arguments passed to lm_robust for MM/AMCE estimation. If .se_type_2 is NULL, estimatr defaults are used.

.auto_cluster

Logical; if TRUE (default) and an id column is present while no clusters are provided, cluster automatically. Only applied when the corresponding .se_type_* is NULL.

.seed

Optional integer; if supplied, sets a temporary RNG seed for simulation/bootstrap and restores prior state on exit.

Value

A projoint_results object containing:

See Also

projoint, pj_estimate, organize_data, projoint_results


Create a projoint_qoi Object

Description

Internal constructor for projoint_qoi objects. A projoint_qoi stores the specification of custom quantities of interest (QOIs) for conjoint estimation. Typically called by set_qoi rather than directly.

Usage

projoint_qoi(...)

Arguments

...

Named elements specifying QOI details, such as:

  • structure: Analysis level ("profile_level" or "choice_level").

  • estimand: Quantity of interest ("mm" or "amce").

  • attribute_of_interest, levels_of_interest, etc.

Value

A list of QOI specifications with class "projoint_qoi".


Create a projoint_results Object

Description

Internal constructor for projoint_results objects. A projoint_results stores the outputs of a conjoint analysis, including estimated effects and metadata about the analysis settings. It is normally generated by projoint and not called directly.

Usage

projoint_results(...)

Arguments

...

Named elements, typically including:

  • estimates: A data frame of estimated effects (point estimates, standard errors, confidence intervals).

  • labels: Attribute/level label mappings from the design.

  • structure: Either "profile_level" or "choice_level".

  • estimand: Either "mm" (marginal mean) or "amce" (average marginal component effect).

  • irr: Intra-respondent reliability value used.

  • tau: Estimated \tau value from IRR correction.

  • se_method: Method used for standard errors.

Value

A list with class "projoint_results" containing estimates and associated metadata. This object is the standard output of projoint and is accepted by plotting and summary methods.


Read and re-format a Qualtrics CSV (choice text)

Description

Reads a CSV file exported from Qualtrics (with "Use choice text" enabled) and returns a data frame formatted for downstream processing with reshape_projoint.

Usage

read_Qualtrics(.file)

Arguments

.file

A character string giving the path to a Qualtrics CSV file.

Value

A data frame where column names are preserved from the Qualtrics export. The first two rows of Qualtrics metadata are skipped automatically.

See Also

reshape_projoint

Examples


# Write a tiny dummy Qualtrics-style CSV to a temp file
tmp <- tempfile(fileext = ".csv")
readr::write_csv(
  data.frame(Q1 = c("Choice Text", "Choice Text", "A", "B")),
  tmp
)
# Read it back in
df <- read_Qualtrics(tmp)
head(df)



Read and apply a reordered attribute/level mapping

Description

Reads a CSV containing a revised ordering of attributes and levels and applies it to an existing projoint_data object. Typical workflow: first save the current labels to CSV (e.g., with save_labels), manually reorder rows (and/or the attribute grouping) in the CSV, then call read_labels() to apply.

Usage

read_labels(.data, .filename)

Arguments

.data

A projoint_data object whose labels/data should be reordered.

.filename

Path to the revised labels CSV (originally produced from the package's labels).

Value

A projoint_data object with the same content as .data but with attributes and levels reordered to match the CSV. The returned object contains:

See Also

save_labels, reshape_projoint

Examples


# Create a projoint_data object from the example dataset
data(exampleData1)
outcomes <- c(paste0("choice", 1:8), "choice1_repeated_flipped")
pj <- reshape_projoint(exampleData1, outcomes)

# Write current labels to a temporary CSV, adding an 'order' column
tmp <- tempfile(fileext = ".csv")
pj$labels |>
  dplyr::mutate(order = dplyr::row_number()) |>
  readr::write_csv(tmp)

# (User would reorder rows in 'tmp' manually; we just read it back)
pj_reordered <- read_labels(pj, tmp)

# Inspect the updated label order
head(pj_reordered$labels)



Reshape survey response data for conjoint analysis (single task set)

Description

Takes a wide survey data frame (e.g., from read_Qualtrics) and reshapes it so that each row corresponds to a single respondent–task–profile. Supports arbitrary ordering of base tasks and a single repeated task per respondent. The repeated base task is inferred from the first base outcome in .outcomes, and the repeated outcome must be the last element of .outcomes.

Usage

reshape_projoint(
  .dataframe,
  .outcomes,
  .choice_labels = c("A", "B"),
  .alphabet = "K",
  .idvar = "ResponseId",
  .repeated = TRUE,
  .flipped = TRUE,
  .covariates = NULL,
  .fill = FALSE
)

Arguments

.dataframe

A data frame, preferably from read_Qualtrics.

.outcomes

Character vector of outcome column names in the asked order. If a repeated task is used, its outcome must be the last element.

.choice_labels

Character vector (default c("A","B")) giving the two labels that appear at the end of the outcome strings.

.alphabet

Single character (default "K") indicating the Qualtrics prefix.

.idvar

Character (default "ResponseId") indicating the respondent id column.

.repeated

Logical (default TRUE) indicating whether a repeated task is present.

.flipped

Logical (default TRUE) indicating whether the repeated task flips profiles before agreement is computed.

.covariates

Optional character vector of respondent-level covariate column names to carry through.

.fill

Logical (default FALSE). If TRUE, fills agree within respondent across tasks as described under “Filling agreement”.

Details

Scope and assumptions

Expected input (Qualtrics K-codes)

Outcome columns (.outcomes)

Choice parsing

Output

Filling agreement

Diagnostics

Value

A projoint_data object with elements $labels and $data; see Details.

See Also

make_projoint_data, projoint

Examples


# Base tasks asked in numeric order; repeated task corresponds to task 1
data(exampleData1)
outcomes <- c(paste0("choice", 1:8), "choice1_repeated_flipped")
reshaped <- reshape_projoint(exampleData1, outcomes)
dplyr::count(reshaped$data, task, profile)  # should be 2 per task



Save attribute and level labels to a CSV file

Description

Saves the attributes and levels (and their order) from a projoint_data object, as generated by reshape_projoint, to a CSV file. This enables manual reordering and later re-import via read_labels.

Usage

save_labels(.data, .filename)

Arguments

.data

A projoint_data object.

.filename

A character string giving the name of a CSV file to be written.

Value

No return value, called for side effects (writes a CSV file).

See Also

read_labels, reshape_projoint

Examples


library(projoint)
data(exampleData1)
reshaped <- reshape_projoint(
  exampleData1,
  .outcomes = c(paste0("choice", 1:8), "choice1_repeated_flipped")
)
tmpfile <- tempfile(fileext = ".csv")
save_labels(reshaped, tmpfile)
readLines(tmpfile, n = 5)  # show first few lines



Set the quantities of interest (QoIs)

Description

Constructs a quantities-of-interest (QoI) specification for projoint. Use this to request specific estimands—marginal means (MMs) or average marginal component effects (AMCEs)—at either the choice- or profile-level, and to declare which attribute levels are compared (including baselines).

Usage

set_qoi(
  .structure = "choice_level",
  .estimand = "mm",
  .att_choose,
  .lev_choose,
  .att_notchoose = NULL,
  .lev_notchoose = NULL,
  .att_choose_b = NULL,
  .lev_choose_b = NULL,
  .att_notchoose_b = NULL,
  .lev_notchoose_b = NULL
)

Arguments

.structure

Either "choice_level" (default) or "profile_level".

.estimand

Either "mm" for marginal means or "amce" for average marginal component effects.

.att_choose

Character scalar: the attribute (column) for the level(s) that are chosen.

.lev_choose

Character vector: the level id(s) for the chosen side. Length 1 for profile-level, \ge1 for choice-level.

.att_notchoose

Character scalar: the attribute (column) for the level(s) that are not chosen. Only used for .structure == "choice_level".

.lev_notchoose

Character vector: the level id(s) for the not chosen side. Length 1 for profile-level, \ge1 for choice-level. Only used for .structure == "choice_level".

.att_choose_b

Character scalar: baseline attribute for the chosen side when computing AMCEs.

.lev_choose_b

Character vector: baseline level id(s) for the chosen side when computing AMCEs. Length 1 for profile-level, \ge1 for choice-level.

.att_notchoose_b

Character scalar: baseline attribute for the not-chosen side (choice-level only) when computing AMCEs.

.lev_notchoose_b

Character vector: baseline level id(s) for the not-chosen side (choice-level only) when computing AMCEs.

Value

A projoint_qoi object (list-like) containing fields such as: structure, estimand, attribute_of_interest, levels_of_interest, and their baseline counterparts. This object can be supplied to downstream estimation helpers that accept a QoI spec.

Examples

# Specify a simple choice-level MM comparison for att1 levels:
q_mm <- set_qoi(
  .structure  = "choice_level",
  .estimand   = "mm",
  .att_choose = "att1",
  .lev_choose = c("att1:lev2"),
  .att_notchoose = "att1",
  .lev_notchoose = c("att1:lev1")
)
str(q_mm)

# Example AMCE with explicit baselines (profile-level):
q_amce <- set_qoi(
  .structure   = "profile_level",
  .estimand    = "amce",
  .att_choose  = "att2",
  .lev_choose  = "att2:lev3",
  .att_choose_b = "att2",
  .lev_choose_b = "att2:lev1"
)
str(q_amce)

Summary for projoint_data

Description

Custom summary method for objects of class projoint_data. Prints a brief overview of the main data and attribute-level labels contained in the object.

Usage

## S3 method for class 'projoint_data'
summary(object, ...)

Arguments

object

A projoint_data object.

...

Additional arguments (currently unused).

Value

No return value, called for its side effect of printing a summary of the projoint_data object to the console.

Examples


data(exampleData1)
dat <- reshape_projoint(
  exampleData1,
  .outcomes = c("choice1", "choice2")
)
summary(dat)


Summary method for projoint_results

Description

Creates a concise tabular summary of a projoint_results object, including the chosen estimand, analysis structure, standard-error settings, and a data frame of estimates.

Usage

## S3 method for class 'projoint_results'
summary(object, ...)

Arguments

object

An object of class projoint_results.

...

Additional arguments (ignored).

Value

A data frame (often a tibble) summarizing the estimated effects. At minimum, it contains the columns produced in object$estimates (e.g., attribute/level identifiers and the point estimate with its standard error and confidence interval in columns such as estimate, std.error, conf.low, conf.high). This table is suitable for further processing or printing.

Examples


  data(exampleData1)

  # Reshape data for two base tasks + repeated (for IRR estimation)
  dat <- reshape_projoint(
    exampleData1,
    .outcomes = c("choice1", "choice2", "choice1_repeated_flipped")
  )

  # Build a valid choice-level QoI
  att <- unique(dat$labels$attribute_id)[1]
  lev_ids   <- dat$labels$level_id[dat$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]
  )

  # Fit model
  fit <- projoint(dat, .qoi = q)

  # Get the tabular summary of estimates
  tab <- summary(fit)
  head(tab)


Summary method for projoint_tau objects

Description

Custom summary method for objects of class projoint_tau, typically created by projoint or related functions. Summarizes intra-respondent reliability (IRR) estimates.

Usage

## S3 method for class 'projoint_tau'
summary(object, ...)

Arguments

object

An object of class projoint_tau.

...

Additional arguments (currently unused).

Value

A tibble (data frame) showing IRR estimates, typically by the number of differing attributes, as stored in object$irr.

Examples

toy_tau <- structure(
  list(irr = data.frame(predicted = 0.413, se = 0.02, n = 200)),
  class = "projoint_tau"
)
summary(toy_tau)