Skip to content

Commit 924c63f

Browse files
authored
Merge pull request #47 from jhelvy/preserve-attributes
Preserve attributes and use standard encoding
2 parents 76be132 + b1bf178 commit 924c63f

38 files changed

Lines changed: 2672 additions & 1433 deletions

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: cbcTools
22
Title: Design and Analyze Choice-Based Conjoint Experiments
3-
Version: 0.6.4
3+
Version: 0.7.0
44
Maintainer: John Helveston <john.helveston@gmail.com>
55
Authors@R: c(
66
person(given = "John",

NAMESPACE

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
S3method("[",cbc_choices)
4+
S3method("[",cbc_design)
5+
S3method("[",cbc_profiles)
6+
S3method("[<-",cbc_choices)
7+
S3method("[<-",cbc_design)
8+
S3method("[<-",cbc_profiles)
9+
S3method("names<-",cbc_choices)
10+
S3method("names<-",cbc_design)
11+
S3method("names<-",cbc_profiles)
312
S3method(plot,cbc_power)
413
S3method(print,cbc_choices)
514
S3method(print,cbc_comparison)
@@ -13,6 +22,7 @@ export(cbc_choices)
1322
export(cbc_compare)
1423
export(cbc_decode)
1524
export(cbc_design)
25+
export(cbc_encode)
1626
export(cbc_inspect)
1727
export(cbc_power)
1828
export(cbc_priors)

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# cbcTools (development version)
22

3+
# cbcTools 0.7.0
4+
5+
- Re-configures the design encoding to use "standard" coding by default.
6+
- Reasoning for standard coding by default is for easier interpretation of summary metrics like balance and overlap.
7+
- New function `cbc_encode()` used to convert designs to dummy or effects coding.
8+
39
# cbcTools 0.6.4
410

511
- Adds `balance_by` argument to force balanced sampling in designs with restricted or otherwise unbalanced levels across attributes.

R/choices.R

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ cbc_choices <- function(design, priors = NULL) {
4646
stop("design must be a cbc_design object created by cbc_design()")
4747
}
4848

49+
# Store original encoding
50+
original_encoding <- attr(design, "encoding") %||% "standard"
51+
4952
if (is.null(priors)) {
5053
# Simulate random choices
5154
result <- simulate_random_choices(design)
@@ -66,8 +69,8 @@ cbc_choices <- function(design, priors = NULL) {
6669
priors_used <- TRUE
6770
}
6871

69-
# Preserve encoding attributes
70-
attr(result, "is_dummy_coded") <- attr(design, "is_dummy_coded")
72+
# Preserve encoding and categorical structure attributes
73+
attr(result, "encoding") <- original_encoding
7174
attr(result, "categorical_structure") <- attr(
7275
design,
7376
"categorical_structure"
@@ -158,27 +161,28 @@ simulate_utility_based_choices <- function(design, priors) {
158161
# Create optimization environment using the existing function
159162
opt_env <- setup_optimization_environment(
160163
profiles = profiles,
161-
method = "random", # Hard-code this so that the obsID vectors are correct
162-
time_start = Sys.time(), # Not important for choice simulation
164+
method = "random",
165+
time_start = Sys.time(),
163166
n_alts = design_params$n_alts,
164167
n_q = design_params$n_q,
165168
n_resp = design_params$n_resp,
166169
n_blocks = design_params$n_blocks,
167-
n_cores = 1, # Not used for choice simulation
168-
n_start = 1, # Not used for choice simulation
169-
max_iter = 1, # Not used for choice simulation
170-
priors = priors, # The new priors for choice simulation
170+
n_cores = 1,
171+
n_start = 1,
172+
max_iter = 1,
173+
priors = priors,
171174
no_choice = design_params$no_choice,
172175
label = design_params$label,
173-
balance_by = NULL, # Not used for choice simulation
174-
remove_dominant = FALSE, # Not needed for choice simulation
175-
dominance_types = NULL, # Not needed for choice simulation
176-
dominance_threshold = 0.8, # Not needed for choice simulation
177-
max_dominance_attempts = 1, # Not needed for choice simulation
178-
randomize_questions = TRUE, # Not used for choice simulation
179-
randomize_alts = TRUE, # Not used for choice simulation
180-
include_probs = FALSE, # Not used for choice simulation
181-
use_idefix = FALSE # Not used for choice simulation
176+
balance_by = NULL,
177+
remove_dominant = FALSE,
178+
dominance_types = NULL,
179+
dominance_threshold = 0.8,
180+
max_dominance_attempts = 1,
181+
randomize_questions = TRUE,
182+
randomize_alts = TRUE,
183+
include_probs = FALSE,
184+
use_idefix = FALSE,
185+
coding = design_params$coding %||% "standard"
182186
)
183187

184188
# Get design matrix from the design object
@@ -217,16 +221,16 @@ get_design_matrix_from_design_object <- function(design, opt_env) {
217221
# Fill matrix from profileID data
218222
for (obs in 1:n_questions) {
219223
obs_rows <- regular_design[regular_design$obsID == obs, ]
220-
obs_rows <- obs_rows[order(obs_rows$altID), ] # Ensure proper order
224+
obs_rows <- obs_rows[order(obs_rows$altID), ]
221225

222-
if (nrow(obs_rows) == n_alts) {
223-
design_matrix[obs, ] <- obs_rows$profileID
224-
} else {
226+
if (nrow(obs_rows) != n_alts) {
225227
stop(sprintf(
226-
"Inconsistent number of alternatives in observation %d",
227-
obs
228+
"Inconsistent number of alternatives in observation %d: expected %d, got %d",
229+
obs, n_alts, nrow(obs_rows)
228230
))
229231
}
232+
233+
design_matrix[obs, ] <- obs_rows$profileID
230234
}
231235

232236
return(design_matrix)

R/compare.R

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,10 @@ extract_comparison_data <- function(designs, design_names, metrics) {
200200
return(comparison_df)
201201
}
202202

203-
# Extract structural metrics
204203
extract_structure_metrics <- function(design) {
205204
params <- attr(design, "design_params")
206205
summary_info <- attr(design, "design_summary")
206+
encoding <- params$encoding %||% "standard"
207207

208208
list(
209209
method = params$method,
@@ -216,7 +216,8 @@ extract_structure_metrics <- function(design) {
216216
profile_usage_pct = round(summary_info$profile_usage_rate * 100, 1),
217217
generation_time = round(params$time_elapsed_sec, 3),
218218
no_choice = params$no_choice,
219-
labeled = !is.null(params$label)
219+
labeled = !is.null(params$label),
220+
encoding = encoding
220221
)
221222
}
222223

@@ -242,30 +243,34 @@ extract_efficiency_metrics <- function(design) {
242243
return(result)
243244
}
244245

245-
# Extract balance metrics
246246
extract_balance_metrics <- function(design) {
247+
# Convert to standard encoding for accurate metrics
248+
design_standard <- get_standard_encoding(design)
249+
247250
summary_info <- attr(design, "design_summary")
248251

249252
if (!is.null(summary_info$efficiency$balance_score)) {
250253
balance_score <- round(summary_info$efficiency$balance_score, 3)
251254
} else {
252255
# Compute on the fly if not available
253-
balance_result <- compute_balance_metrics_internal(design)
256+
balance_result <- compute_balance_metrics_internal(design_standard)
254257
balance_score <- round(balance_result$overall_balance, 3)
255258
}
256259

257260
list(balance_score = balance_score)
258261
}
259262

260-
# Extract overlap metrics
261263
extract_overlap_metrics <- function(design) {
264+
# Convert to standard encoding for accurate metrics
265+
design_standard <- get_standard_encoding(design)
266+
262267
summary_info <- attr(design, "design_summary")
263268

264269
if (!is.null(summary_info$efficiency$overlap_score)) {
265270
overlap_score <- round(summary_info$efficiency$overlap_score, 3)
266271
} else {
267272
# Compute on the fly if not available
268-
overlap_result <- compute_overlap_metrics_internal(design)
273+
overlap_result <- compute_overlap_metrics_internal(design_standard)
269274
overlap_score <- round(overlap_result$overall_overlap, 3)
270275
}
271276

R/decode.R

Lines changed: 0 additions & 168 deletions
This file was deleted.

R/depreciated.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#' Convert dummy-coded CBC data back to categorical format
2+
#'
3+
#' This function is depreciated. Use `cbc_encode()` instead
4+
#'
5+
#' @param data A `cbc_design` or `cbc_choices` object with dummy-coded categorical variables
6+
#' @return The input object with categorical variables restored to their original format
7+
#' @export
8+
cbc_decode <- function(data) {
9+
# v0.6.5
10+
.Deprecated(
11+
"This function was depreciated in v0.13.0; use the cbc_encode() function instead"
12+
)
13+
}

0 commit comments

Comments
 (0)