# Diseño de experimentos y estimación avanzada: cbcTools y logitr
```{r}
#| echo: false
#| message: false
#| warning: false
source("script.R")
```
## Introducción: diseñar antes de recoger, estimar con más flexibilidad
El capítulo anterior partió de una encuesta CBC ya recogida, con un diseño de
tareas de elección generado de forma simplificada (combinaciones aleatorias de
niveles). En un proyecto real, el **diseño del experimento** —qué perfiles
concretos se muestran a cada encuestado, en qué combinaciones, con qué grado de
equilibrio estadístico— es una decisión metodológica crítica que precede a la
recogida de datos, y de la que depende directamente la calidad de las
estimaciones posteriores. Además, el modelo logit condicional estimado con
`mlogit` es la base, pero no agota las posibilidades de modelado: existen
parametrizaciones alternativas que abordan limitaciones del modelo logit
condicional estándar.
Estas dos cuestiones son precisamente el objeto de dos paquetes de R
desarrollados por **John Paul Helveston** (Universidad George Washington):
`cbcTools`, para el diseño y la evaluación de experimentos CBC antes de su
lanzamiento al campo, y `logitr`, para la estimación rápida de modelos logit con
parametrizaciones alternativas a las de `mlogit` [@Helveston2023logitr;
@Helveston2023cbctools]. Ambos paquetes no sustituyen a `mlogit` —que sigue
siendo el estándar académico de referencia desarrollado en el capítulo
anterior—, sino que lo complementan: `cbcTools` interviene *antes* de la
recogida de datos, en la fase de diseño; `logitr` ofrece una alternativa de
estimación *más rápida y con parametrizaciones adicionales* una vez los datos ya
están disponibles.
## Diseño de experimentos CBC con cbcTools
Antes de salir a campo, es necesario decidir qué perfiles concretos se
presentarán a cada encuestado y en qué tareas de elección se agruparán. Un
diseño deficiente —por ejemplo, uno en el que dos niveles de un atributo
aparezcan siempre juntos— puede hacer que sea estadísticamente imposible separar
sus efectos individuales sobre la utilidad. El paquete `cbcTools` automatiza
este proceso siguiendo un flujo de varios pasos: generar el universo de perfiles
posibles, generar el diseño del experimento, inspeccionar su calidad
estadística, y simular las elecciones que produciría una muestra de encuestados
antes incluso de salir a campo [@Helveston2023cbctools].
### Generación del universo de perfiles
```{r}
#| echo: true
#| message: false
# Step 1: generate the universe of all possible profiles from the attribute levels
ebook_profiles <- cbcTools::cbc_profiles(
storage = c("8GB", "16GB"),
screen = c("5in", "6in", "7in"),
color = c("Black", "White", "Silver"),
price = c(99, 129, 159)
)
head(ebook_profiles)
```
### Generación del diseño del experimento
```{r}
#| echo: true
# Step 2: generate a randomized design (3 alternatives per choice task, 8 tasks per respondent)
ebook_design_cbctools <- cbcTools::cbc_design(
profiles = ebook_profiles,
n_resp = 200,
n_alts = 3,
n_q = 8
)
head(ebook_design_cbctools)
```
### Evaluación de la calidad del diseño
Una vez generado el diseño, `cbcTools` permite inspeccionar su calidad
estadística antes de recoger ningún dato real, comprobando el balance y el
solapamiento de niveles entre alternativas:
```{r}
#| echo: true
cbcTools::cbc_inspect(ebook_design_cbctools, c("balance", "overlap"))
```
Un diseño bien equilibrado presenta cada nivel de cada atributo con una
frecuencia similar a lo largo de todas las tareas de elección, y evita que el
mismo nivel se repita en exceso dentro de una misma tarea (lo que dificulta
distinguir su efecto del de otros atributos). `cbcTools` también permite
**simular elecciones** a partir de unos coeficientes hipotéticos —antes de tener
datos reales—, lo que resulta especialmente útil para realizar un análisis de
potencia: estimar cuántos encuestados serían necesarios para detectar con
suficiente precisión el efecto esperado de cada atributo
[@Helveston2023cbctools].
::: callout-tip
## Cuándo usar cbcTools
`cbcTools` interviene en la fase de **diseño**, antes de la recogida de datos.
Su uso es relevante cuando se está planificando un nuevo estudio CBC y se
necesita decidir el número de tareas de elección, el número de alternativas por
tarea, o evaluar la calidad estadística de un diseño antes de su lanzamiento. No
participa en la estimación del modelo a partir de datos ya recogidos, que es la
función de paquetes como `mlogit` (capítulo anterior) o `logitr` (siguiente
sección de este capítulo).
:::
## Estimación con logitr: parametrización en espacio de disposición a pagar
El modelo logit condicional estimado en el capítulo anterior con `mlogit` se
especifica en lo que se conoce como **espacio de preferencias** (*preference
space*): se estima un coeficiente para cada atributo y, por separado, un
coeficiente para el precio, y la disposición a pagar se calcula *después* de la
estimación, dividiendo cada coeficiente de atributo entre el coeficiente de
precio (con signo cambiado).
`logitr` permite, además de reproducir esta misma parametrización, estimar el
modelo directamente en el **espacio de disposición a pagar** (*WTP space*): en
lugar de estimar coeficientes de utilidad y calcular la disposición a pagar a
posteriori, el modelo estima directamente los parámetros de disposición a pagar
como parte del propio proceso de optimización [@Helveston2023logitr]. Esta
reparametrización resulta especialmente relevante en modelos con heterogeneidad
de preferencias entre individuos (modelos logit mixtos), donde el cálculo de la
disposición a pagar a partir de coeficientes en espacio de preferencias puede
producir estimaciones con una varianza excesiva o poco interpretables
[@Helveston2023logitr].
### Preparación de los datos
Se simula un conjunto de datos CBC con la misma estructura del capítulo
anterior, de forma autocontenida en este capítulo:
```{r}
#| echo: true
#| message: false
set.seed(7)
n_respondents <- 200
n_tasks <- 8
n_alternatives <- 3
storage_levels <- c("8GB", "16GB")
screen_levels <- c("5in", "6in", "7in")
color_levels <- c("Black", "White", "Silver")
price_levels <- c(99, 129, 159)
true_utilities <- c(
storage16GB = 0.9,
screen6in = 0.5, screen7in = 0.3,
colorWhite = 0.2, colorSilver = 0.4,
price = -0.025
)
ebook_design <- expand.grid(
resp_id = 1:n_respondents,
task_id = 1:n_tasks,
alt_id = 1:n_alternatives
) |>
dplyr::arrange(resp_id, task_id, alt_id) |>
dplyr::mutate(
storage = sample(storage_levels, dplyr::n(), replace = TRUE),
screen = sample(screen_levels, dplyr::n(), replace = TRUE),
color = sample(color_levels, dplyr::n(), replace = TRUE),
price = sample(price_levels, dplyr::n(), replace = TRUE)
)
ebook_design <- ebook_design |>
dplyr::mutate(
utility = dplyr::if_else(storage == "16GB", true_utilities["storage16GB"], 0) +
dplyr::case_when(
screen == "6in" ~ true_utilities["screen6in"],
screen == "7in" ~ true_utilities["screen7in"],
TRUE ~ 0
) +
dplyr::case_when(
color == "White" ~ true_utilities["colorWhite"],
color == "Silver" ~ true_utilities["colorSilver"],
TRUE ~ 0
) +
price * true_utilities["price"] +
rnorm(dplyr::n(), 0, 1)
)
ebook_data <- ebook_design |>
dplyr::group_by(resp_id, task_id) |>
dplyr::mutate(choice = as.integer(utility == max(utility))) |>
dplyr::ungroup() |>
dplyr::select(resp_id, task_id, alt_id, storage, screen, color, price, choice)
# logitr requires a choice-task identifier that is unique across the entire
# dataset (not just within each respondent), since task_id alone repeats
# across all 200 respondents.
ebook_data <- ebook_data |>
dplyr::mutate(obs_id_chr = paste(resp_id, task_id, sep = "_"))
ebook_data$obs_id <- as.integer(factor(ebook_data$obs_id_chr))
ebook_data$obs_id_chr <- NULL
head(ebook_data, 9)
```
Como en el capítulo anterior, se convierten explícitamente a `factor` las
variables categóricas, con el orden de niveles fijado, para garantizar que el
modelo nombre los coeficientes con las etiquetas reales:
```{r}
#| echo: true
ebook_data <- ebook_data |>
dplyr::mutate(
storage = factor(storage, levels = c("8GB", "16GB")),
screen = factor(screen, levels = c("5in", "6in", "7in")),
color = factor(color, levels = c("Black", "White", "Silver"))
)
```
### Estimación en espacio de preferencias
Se estima primero el modelo en espacio de preferencias, equivalente al estimado
con `mlogit` en el capítulo anterior. Al igual que con `mlogit`, se fuerza
explícitamente `contr.treatment` para garantizar que los coeficientes se nombren
con las etiquetas reales de cada nivel, con independencia de la configuración de
contrastes de la sesión:
```{r}
#| echo: true
#| message: false
old_contrasts <- options("contrasts")
options(contrasts = c("contr.treatment", "contr.poly"))
cbc_model_logitr <- logitr::logitr(
data = ebook_data,
outcome = "choice",
obsID = "obs_id",
pars = c("storage", "screen", "color", "price")
)
options(old_contrasts)
summary(cbc_model_logitr)
```
Los coeficientes estimados son sustancialmente equivalentes a los obtenidos con
`mlogit` en el capítulo anterior.
### Estimación en espacio de disposición a pagar
`logitr` permite reestimar directamente el mismo modelo en espacio de
disposición a pagar, especificando qué variable representa el precio mediante el
argumento `scalePar`:
```{r}
#| echo: true
#| message: false
old_contrasts <- options("contrasts")
options(contrasts = c("contr.treatment", "contr.poly"))
cbc_model_wtp <- logitr::logitr(
data = ebook_data,
outcome = "choice",
obsID = "obs_id",
pars = c("storage", "screen", "color"),
scalePar = "price"
)
options(old_contrasts)
summary(cbc_model_wtp)
```
En esta parametrización, los coeficientes estimados **son ya directamente la
disposición a pagar**, expresada en las mismas unidades que el precio (euros),
sin necesidad del cálculo posterior que se hizo manualmente con los coeficientes
de `mlogit` en el capítulo anterior.
```{r}
#| echo: true
logitr::wtp(cbc_model_logitr, scalePar = "price")
```
La función `logitr::wtp()` permite además calcular la disposición a pagar a
partir de un modelo en espacio de preferencias —de forma análoga al cálculo
manual realizado en el capítulo anterior con `mlogit`—, confirmando la
coherencia entre ambas vías de estimación.
::: callout-tip
## Cuándo usar logitr
`logitr` es una alternativa de estimación, no de diseño. Resulta especialmente
útil cuando: (1) se necesita una parametrización directa en espacio de
disposición a pagar, evitando el cálculo posterior y sus problemas de varianza
en modelos con heterogeneidad; (2) se va a estimar un modelo logit mixto con
parámetros aleatorios entre individuos, donde `logitr` ofrece tiempos de
estimación significativamente menores que `mlogit`; o (3) se necesita estimar un
modelo ponderado, asignando distinto peso a distintas observaciones de la
muestra.
:::
## Síntesis: tres paquetes, tres momentos del análisis CBC
| Paquete | Fase del análisis | Función principal | Autor de referencia |
|:-----------------|:-------------------|:-------------------|:---------------------|
| `cbcTools` | Diseño del experimento | Generar y evaluar el diseño antes de recoger datos | Helveston |
| `mlogit` | Estimación (espacio de preferencias) | Estándar académico de referencia para el modelo logit condicional | Croissant |
| `logitr` | Estimación (preferencias o WTP) | Estimación rápida, con parametrización directa en disposición a pagar | Helveston |
Los tres paquetes son complementarios, no excluyentes: un flujo de trabajo
completo en un proyecto CBC real combinaría `cbcTools` en la fase de diseño del
cuestionario, y `mlogit` o `logitr` en la fase de estimación del modelo, según
las necesidades concretas del análisis —siendo `logitr` la opción preferible
cuando se trabaja con modelos en espacio de disposición a pagar o con
heterogeneidad de preferencias entre individuos.
### Conclusiones
Este capítulo ha mostrado el ecosistema de herramientas que complementa al
análisis CBC desarrollado en el capítulo anterior: `cbcTools` para diseñar y
evaluar experimentos antes de recoger datos, y `logitr` para estimar modelos
logit con parametrizaciones adicionales —en particular, la estimación directa en
espacio de disposición a pagar—. El capítulo siguiente desarrolla una variante
distinta de la misma familia de modelos: el MaxDiff, orientado a la priorización
de listas de elementos no combinables en productos.