# Cargar paquetes (instala pacman si no lo tienes)
if (!require("pacman")) install.packages("pacman")
pacman::p_load(cluster, factoextra, corrplot, rio, tidyverse)
# Importar y limpiar datos
df <- import("StateData.xlsx") %>% as_tibble()
# Seleccionar variables de Google Search y preparar matriz
# Seleccionar variables de Google Search y Personalidad
df_num <- df %>%
select(
state_code,
extraversion, agreeableness, conscientiousness, neuroticism, openness, # Ajusta los nombres exactos
instagram:modernDance
) %>%
column_to_rownames("state_code") %>%
na.omit() # Eliminar valores faltantes si los hay
# Estandarizar variables (Media 0, Varianza 1)
# Aunque las variables de Google ya son Z-scores, scale() asegura que
# cualquier variable adicional (como las psicológicas T-scores) comparta la misma métrica.
Z <- scale(df_num)Clustering + Discriminat Analysis + Conjoint Analysis
Clustering
Descripción del Conjunto de Datos
Para la aplicación del clustering se ha hecho uso de la base de datos StateData.xlsx, el cual fue compilado para realizar comparaciones a nivel nacional e incluye cuatro categorías principales de datos para los 48 estados contiguos de Estados Unidos.
Alaska, Hawái y el Distrito de Columbia fueron excluidos debido a la falta de datos sobre sus regiones psicológicas.
Las variables se dividen en las siguientes categorías:
- Datos Geográficos: Incluye el nombre común del estado, su código postal de dos letras y la región censal a la que pertenece (Noreste, Medio Oeste, Sur y Oeste).
- Datos Políticos: Indica si el gobernador del estado, a fecha del 26 de julio de 2018, era Demócrata o Republicano.
- Datos de Personalidad: Clasifica a los estados en tres perfiles (“Amistoso y Convencional”, “Relajado y Creativo”, “Temperamental y Desinhibido”) y proporciona puntuaciones en los Cinco Grandes Rasgos de la Personalidad (Extraversión, Amabilidad, Responsabilidad, Neuroticismo y Apertura). Estos rasgos psicológicos están reportados como puntuaciones T estandarizadas (media de 50 y desviación estándar de 10).
- Datos de Búsqueda en Google: Mide la popularidad relativa de 12 términos de búsqueda (como instagram, entrepreneur, volunteering, museum) seleccionados por su relación aproximada con los rasgos de personalidad. Se reportan como puntuaciones Z estandarizadas (media de 0 y desviación estándar de 1).
Objetivo
El objetivo principal de esta primera sección es aplicar algoritmos de clustering para descubrir patrones y similitudes latentes entre los estados. Al agrupar los datos utilizando las variables numéricas continuas (rasgos de personalidad y comportamiento de búsqueda en Google), buscaremos identificar si existen “regiones psicosociales” que compartan perfiles de comportamiento similares, independientemente de sus fronteras geográficas o políticas tradicionales.
Preparación de los Datos
En esta sección cargaremos los datos y prepararemos las variables continuas para el algoritmo de agrupamiento. Es crucial recordar que las variables de personalidad y de Google Search ya se encuentran en distintas escalas (puntuaciones T y Z, respectivamente), por lo que el preprocesamiento garantizará que todas tengan el mismo peso durante el cálculo de distancias.
Análisis Exploratorio: Matriz de Correlaciones
Antes de agrupar, visualizamos cómo se relacionan los términos de búsqueda entre sí.
Evaluación del Número Óptimo de Conglomerados (K)
Utilizamos el método del Codo (WSS) y el estadístico Silhouette para determinar el número ideal de clústeres.
# Método del codo
fviz_nbclust(Z, FUNcluster = hcut, method = "wss") +
labs(title = "Método del Codo (WSS)", x = "Número de clústeres K")
# Método Silhouette
fviz_nbclust(Z, FUNcluster = hcut, method = "silhouette") +
labs(title = "Método Silhouette", x = "Número de clústeres K")Clustering Jerárquico (Método de Ward)
El método de Ward minimiza la varianza dentro de cada clúster, creando grupos más compactos y balanceados en comparación con otros métodos de enlace.
# Calcular distancia euclidiana
D_euclidiana <- dist(Z, method = "euclidean")
# Aplicar clustering jerárquico con método de Ward
hc_ward <- hclust(D_euclidiana, method = "ward.D2"); hc_ward
Call:
hclust(d = D_euclidiana, method = "ward.D2")
Cluster method : ward.D2
Distance : euclidean
Number of objects: 48
# Extraer el K óptimo basado en la métrica Silhouette
sil_info <- fviz_nbclust(Z, FUNcluster = hcut, method = "silhouette")$data
K_optimo <- as.numeric(as.character(sil_info$clusters[which.max(sil_info$y)]))
# Visualizar dendrograma con el K óptimo
fviz_dend(hc_ward, k = K_optimo,
rect = TRUE, show_labels = TRUE, cex = 0.5,
main = paste("Dendrograma de Estados - Método de Ward ( K =", K_optimo, ")"),
ylab = "Distancia", xlab = "Estados")Algoritmo K-Means y Visualización Bidimensional
Aplicamos K-Means, un método de partición, utilizando el mismo número óptimo de grupos. Luego, reducimos las dimensiones de nuestros datos (mediante Componentes Principales internamente) para visualizar los grupos en un plano 2D.
library(plotly)
set.seed(123)
# Aseguramos K=2 que es tu número óptimo
km <- kmeans(Z, centers = 2, nstart = 50)
# 1. Generamos el gráfico base limpio (sin letras sobrepuestas)
p <- fviz_cluster(km, data = Z,
geom = "point",
ellipse.type = "convex",
main = "Agrupamiento K-Means Interactivo (K = 2)")
# 2. Extraemos los datos internos del gráfico para crear nuestra tabla de textos
datos_tooltip <- p$data
# Cruzamos con tu 'df' original para sacar el nombre completo
datos_tooltip$EstadoCompleto <- df$State[match(datos_tooltip$name, df$state_code)]
# 3. Creamos la variable de texto exacto
datos_tooltip$TextoInteractivo <- paste(
"<b>Estado:</b>", datos_tooltip$EstadoCompleto,
"<br><b>Código:</b>", datos_tooltip$name,
"<br><b>Clúster:</b>", datos_tooltip$cluster
)
# 4. EL TRUCO: Añadimos una capa de puntos con alpha = 0 (totalmente transparentes).
# Esta capa tiene sus propios datos exclusivos, por lo que no rompe las elipses.
p_final <- p + geom_point(data = datos_tooltip,
aes(x = x, y = y, text = TextoInteractivo),
alpha = 0)
# 5. Volvemos interactivo el gráfico, apuntando únicamente a nuestro texto
ggplotly(p_final, tooltip = "text") %>%
layout(hoverlabel = list(bgcolor = "white")) # Hace que el cuadro emergente se vea más limpioCaracterización de los Conglomerados (Profiling)
Para entender qué significa cada grupo, graficamos los centroides (medias estandarizadas) de cada clúster. Un valor por encima de 0 indica un interés superior a la media nacional en ese término de búsqueda; un valor por debajo indica menor interés.
# Heatmap de los centroides
heatmap(as.matrix(km$centers),
Rowv = NA, Colv = NA, scale = "none",
col = colorRampPalette(c("blue", "white", "red"))(50),
margins = c(10, 5),
xlab = "Términos de Búsqueda (Google)",
ylab = "Clúster (K-Means)",
main = "Perfil Psicosocial por Clúster")Clúster 1: Perfil “Temperamental, Abierto y Cívico-Cultural”
- Rasgos Psicológicos: Presentan niveles extremadamente bajos en Responsabilidad (conscientiousness) y Amabilidad (agreeableness), marcados con un azul intenso. En contraste, muestran niveles altos (rojo) de Neuroticismo y Apertura a la experiencia (openness).
- Comportamiento Digital (Google): Exhiben un interés superior a la media en temas de privacidad y regulación tecnológica (gdpr, privacy), cultura y compromiso cívico (museum, volunteering, modernDance) e interacción rápida (retweet). Por el contrario, muestran desinterés (azul) en facebook y manualidades tradicionales (scrapbook).
Clúster 2: Perfil “Convencional, Amable y Tradicional”
- Rasgos Psicológicos: Es la imagen especular (el reverso) del primer grupo, aunque con variaciones más suaves (tonos pastel). Tienen puntuaciones positivas (rosado/rojo claro) en Responsabilidad, Amabilidad y Extraversión, y puntuaciones por debajo de la media en Neuroticismo y Apertura.
- Comportamiento Digital (Google): Reflejan un patrón más tradicional. Dominan las búsquedas de facebook y scrapbook, mostrando escaso interés en privacidad de datos, museos, danza moderna o voluntariado (dominado por tonos azules).
El algoritmo K-Means con \(K=2\) divide a los estados de EE. UU. en dos perfiles psicosociales antagónicos. El Clúster 1 agrupa a poblaciones con menor convencionalismo social (baja responsabilidad/amabilidad) pero alta inquietud intelectual, cultural y tecnológica. El Clúster 2 captura el perfil tradicional del “Midwest” o sur estadounidense: sociable, estructurado, amable y orientado a intereses clásicos.
centros <- km$centers
matplot(t(centros), type = "b", pch = 19, lty = 1, lwd = 2,
xaxt = "n", xlab = "Términos de Búsqueda", ylab = "Z-Score Medio",
main = "Comportamiento Promedio por Clúster")
axis(1, at = 1:ncol(centros), labels = colnames(centros), las = 2, cex.axis = 0.8)
abline(h = 0, lty = 2, col = "gray")
legend("topright", legend = paste("Clúster", 1:nrow(centros)),
col = 1:nrow(centros), pch = 19, lty = 1, bty = "n")El gráfico demuestra visualmente que los estados se dividen en dos perfiles completamente opuestos, funcionando casi como un espejo. El Clúster 1 (línea negra) agrupa a los estados “inconformistas y curiosos”: tienen puntuaciones muy bajas en rasgos clásicos como la responsabilidad o amabilidad, pero destacan enormemente por su inquietud cultural, tecnológica y progresista, dominando las búsquedas sobre museos, privacidad de datos (GDPR) y danza moderna.
Por el contrario, el Clúster 2 (línea rosa) representa el perfil “tradicional y estructurado”. Sus habitantes puntúan alto en responsabilidad y amabilidad, mostrando una clara preferencia por intereses más familiares y sociales convencionales, como el uso de Facebook o las manualidades (scrapbook). En resumen, el gráfico ilustra el contraste perfecto entre una población con apertura vanguardista y otra orientada a un conservadurismo social más afable.
Discriminant Analisys
1. Introducción
El presente documento desarrolla un Análisis Discriminante Lineal (LDA) sobre el mercado de suelo urbano en Lima Metropolitana utilizando una base geoespacial de \(N=3,114\) avisos de venta. El objetivo es discriminar geográficamente el valor del suelo, transformando variables altamente asimétricas y verificando si la clasificación por grandes zonas urbanas es superior a la categorización administrativa por distritos.
2. Preparación de Datos y Variables Derivadas
Para este análisis, el valor de suelo y el área presentan una asimetría positiva pronunciada, por lo que se construyen variables derivadas logarítmicas, además de calcular la distancia euclidiana al centro de Lima reproyectando las coordenadas al sistema UTM.
# Cargar librerías necesarias
library(sf)
library(dplyr)
library(MASS)
library(ggplot2)
library(caret)
library(corrplot)
library(biotools)
# 1. Cargar la base de datos
ruta_gpkg <- "lima_metropolitana_ofertas.gpkg"
puntos <- st_read(ruta_gpkg, layer = "lima_metropolitana_ofertas", quiet = TRUE)
# 2. Transformación espacial y creación de variables derivadas
centro_utm <- st_sfc(st_point(c(-77.0428, -12.0464)), crs = 4326) %>%
st_transform(crs = 32718)
datos <- puntos %>%
st_transform(crs = 32718) %>%
mutate(
dist_centro_km = as.numeric(st_distance(., centro_utm)) / 1000,
log_valor = log10(valor_soles_m2),
log_area = log10(area_m2),
distrito = enc2utf8(as.character(distrito))
) %>%
st_drop_geometry()
# 3. Mapeo de Distritos a Zonas de Lima
datos <- datos %>%
mutate(zona_lima = case_when(
distrito %in% c("Carabayllo", "Comas", "Los Olivos", "Puente Piedra",
"San Martin de Porres", "Independencia", "Ancón", "Santa Rosa") ~ "Norte",
distrito %in% c("SJL", "Ate", "Santa Anita", "El Agustino", "Chaclacayo",
"Chosica (Lurigancho)", "La Molina", "Cieneguilla") ~ "Este",
distrito %in% c("Villa El Salvador", "VMT", "SJM", "Chorrillos", "Lurín",
"Pachacamac", "Punta Negra", "Punta Hermosa", "San Bartolo",
"Santa Maria Del Mar", "Pucusana") ~ "Sur",
distrito %in% c("San Isidro", "Miraflores", "San Borja", "Surquillo",
"San Miguel", "Pueblo Libre", "Magdalena Del Mar", "Jesús María",
"Lince", "San Luis", "La Victoria Lim", "Lima Cercado",
"Breña", "Rímac", "Barranco", "Santiago De Surco") ~ "Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(zona_lima)) %>%
mutate(zona_lima = factor(zona_lima))El análisis original planteaba un LDA por distrito, pero varios de los 43 distritos presentan menos de 20 observaciones, lo que viola el supuesto de tamaño muestral por grupo. Por ello, se agrupan en cuatro zonas geográficas balanceadas (Centro, Sur, Norte, Este).
3. Modelo A: LDA por Zona de Lima
Ajustamos el Modelo A utilizando las variables estandarizadas para evitar sesgos por la escala de medición
# Variables para el LDA
vars_lda <- c("log_valor", "log_area", "dist_centro_km")
# Crear dataset específico y estandarizar variables
datosA <- datos %>% dplyr::select(all_of(vars_lda), zona_lima)
datosA[, vars_lda] <- scale(datosA[, vars_lda])
# Ajuste del modelo LDA
modelo_lda <- lda(zona_lima ~ log_valor + log_area + dist_centro_km, data = datosA)
modelo_ldaCall:
lda(zona_lima ~ log_valor + log_area + dist_centro_km, data = datosA)
Prior probabilities of groups:
Centro Este Norte Sur
0.2870906 0.2035967 0.2517662 0.2575466
Group means:
log_valor log_area dist_centro_km
Centro 1.0068021 0.04740055 -0.87306451
Este -0.2365501 0.24022337 -0.05761479
Norte -0.4696221 -0.32452213 0.08960644
Sur -0.4762153 0.07449830 0.93116708
Coefficients of linear discriminants:
LD1 LD2 LD3
log_valor -0.7458555 -1.2033427 0.3548495
log_area -0.1067454 -0.4540127 -0.9304334
dist_centro_km 0.8383191 -1.1791722 0.2968683
Proportion of trace:
LD1 LD2 LD3
0.8182 0.1583 0.0235
Verificación de Supuestos: Prueba M de Box
Evaluamos la homogeneidad de matrices de varianzas-covarianzas utilizando la prueba M de Box.
boxM(datosA[, vars_lda], datosA$zona_lima)
Box's M-test for Homogeneity of Covariance Matrices
data: datosA[, vars_lda]
Chi-Sq (approx.) = 1971.4, df = 18, p-value < 2.2e-16
La prueba rechaza fuertemente la hipótesis nula de homogeneidad de covarianzas (\(p < 2.2 \times 10^{-16}\)). Sin embargo, con un tamaño muestral grande (\(n=3,114\)), la prueba de Box es altamente sensible y tiende a rechazar \(H_0\) ante variaciones menores. El LDA se asume entonces como una herramienta predictiva.
4. Evaluación del Modelo y Visualización
Evaluamos la precisión global del modelo mediante la técnica de validación cruzada Leave-One-Out (LOOCV).
# LOOCV
modelo_cv <- lda(zona_lima ~ log_valor + log_area + dist_centro_km, data = datosA, CV = TRUE)
tab_cv <- table(Observado = datosA$zona_lima, Predicho = modelo_cv$class)
precision_cv <- sum(diag(tab_cv)) / sum(tab_cv)
cat("Precisión del Modelo A (LOOCV):", round(precision_cv * 100, 1), "%\n")Precisión del Modelo A (LOOCV): 58.2 %
tab_cv Predicho
Observado Centro Este Norte Sur
Centro 807 31 56 0
Este 196 125 193 120
Norte 129 63 467 125
Sur 59 98 233 412
El modelo logra una precisión LOOCV del 58.1%. Destaca la zona Centro con una sensibilidad muy alta (90.3%), lo que evidencia que constituye un perfil económico genuinamente distintivo (ubicación cercana y precios altos).
Espacio Discriminante
Visualizamos cómo el LDA separa los grupos proyectando los datos en las dos primeras dimensiones discriminantes (LD1 y LD2).
proy <- predict(modelo_lda)
df_plot <- data.frame(proy$x, zona = datosA$zona_lima)
ggplot(df_plot, aes(x = LD1, y = LD2, color = zona)) +
geom_point(alpha = 0.4, size = 1.2) +
stat_ellipse(level = 0.68, linewidth = 1) +
labs(title = "Espacio discriminante: zonas de Lima",
subtitle = "Elipses de concentración al 68%",
x = "LD1 (81.8% varianza)", y = "LD2 (15.8% varianza)") +
theme_minimal()El primer eje (LD1) concentra el 81.8% de la varianza discriminante total y opone la distancia al centro contra el valor del suelo, capturando la lógica del modelo económico de renta de la tierra (terrenos caros cerca del centro vs. baratos y alejados).
Mapa: Observado vs. Predicho sobre el Territorio
El diagnóstico visual de la clasificación nos permite entender dónde está fallando el modelo espacialmente.
# Recuperar la geometría original y alinearla con las zonas válidas
puntos_mapeo <- puntos %>%
mutate(zona_lima = case_when(
distrito %in% c("Carabayllo", "Comas", "Los Olivos", "Puente Piedra",
"San Martin de Porres", "Independencia", "Ancón", "Santa Rosa") ~ "Norte",
distrito %in% c("SJL", "Ate", "Santa Anita", "El Agustino", "Chaclacayo",
"Chosica (Lurigancho)", "La Molina", "Cieneguilla") ~ "Este",
distrito %in% c("Villa El Salvador", "VMT", "SJM", "Chorrillos", "Lurín",
"Pachacamac", "Punta Negra", "Punta Hermosa", "San Bartolo",
"Santa Maria Del Mar", "Pucusana") ~ "Sur",
distrito %in% c("San Isidro", "Miraflores", "San Borja", "Surquillo",
"San Miguel", "Pueblo Libre", "Magdalena Del Mar", "Jesús María",
"Lince", "San Luis", "La Victoria Lim", "Lima Cercado",
"Breña", "Rímac", "Barranco", "Santiago De Surco") ~ "Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(zona_lima))
# Añadir las predicciones del modelo LDA y clasificar el acierto
puntos_mapeo$zona_pred <- predict(modelo_lda)$class
puntos_mapeo$acierto <- ifelse(puntos_mapeo$zona_lima == puntos_mapeo$zona_pred, "Correcto", "Error")
# Graficar en el territorio real
ggplot(puntos_mapeo) +
geom_sf(aes(color = acierto), alpha = 0.6, size = 0.8) +
scale_color_manual(values = c("Correcto" = "grey70", "Error" = "red")) +
labs(
title = "Aciertos y errores de clasificación del LDA",
subtitle = "Distribución territorial de las predicciones",
color = "Clasificación"
) +
theme_minimal()Modelo B: LDA por Distrito Bruto (Comparación)
A modo de contraste, ajustamos un segundo LDA sin agrupación zonal, utilizando únicamente los distritos con \(n>=50\).
5. Evaluación de Desempeño y Matriz de Confusión
n_por_distrito <- sort(table(datos$distrito), decreasing = TRUE)
distritos_ok <- names(n_por_distrito[n_por_distrito >= 50])
datosB <- datos %>%
filter(distrito %in% distritos_ok) %>%
dplyr::select(all_of(vars_lda), distrito) %>%
mutate(distrito = factor(distrito))
datosB[, vars_lda] <- scale(datosB[, vars_lda])
modelo_B_cv <- lda(distrito ~ log_valor + log_area + dist_centro_km, data = datosB, CV = TRUE)
precision_B_cv <- mean(modelo_B_cv$class == datosB$distrito)
cat("Precisión Modelo B (Distritos - LOOCV):", round(precision_B_cv * 100, 1), "%\n")Precisión Modelo B (Distritos - LOOCV): 43.2 %
6. Cuadro Comparativo de Desempeño (Síntesis)
Compararemos el rendimiento de ambos modelos bajo la técnica de validación cruzada Leave-One-Out (LOOCV).
# Generar tabla resumida de comparación de precisión
resumen_comparativo <- data.frame(
Modelo = c("Modelo A (Zonas de Lima)", paste("Modelo B (Distritos n >=", 50, ")")),
Grupos = c(length(unique(datosA$zona_lima)), length(distritos_ok)),
Precision_LOOCV = c(
paste0(round(precision_cv * 100, 1), "%"),
paste0(round(precision_B_cv * 100, 1), "%")
)
)
knitr::kable(
resumen_comparativo,
col.names = c("Modelo", "N° Grupos", "Precisión LOOCV"),
caption = "Comparación de precisión Leave-One-Out según nivel de agregación territorial"
)| Modelo | N° Grupos | Precisión LOOCV |
|---|---|---|
| Modelo A (Zonas de Lima) | 4 | 58.2% |
| Modelo B (Distritos n >= 50 ) | 24 | 43.2% |
Con las mismas tres variables predictoras, reducir el nivel de agregación de zona a distrito individual empeora la clasificación en 14.9 puntos porcentuales. Esta caída es la evidencia empírica de que distrito es una categoría administrativa demasiado fina para que el precio, el área y la distancia al centro la discriminen de forma estable: el mercado de suelo de Lima se organiza económicamente por zonas amplias, no por los límites político-administrativos de cada distrito.
Conjoint Analysis
Analizaremos los datos de una encuesta en la que se pidió a 15 consumidores que calificaran diez helados. Cada helado tenía un “perfil” diferente, es decir, una combinación distinta de niveles de cuatro atributos:
- sabor (frambuesa, chocolate, fresa, mango, vainilla),
- envase (wafle casero, cono, tarrina),
- bajo en grasa (o no) y
- orgánico (o no).
Los 15 participantes calificaron los diez perfiles con una puntuación entre 1 y 10.
1. Datos icecream
library(readxl)
icecream <- read_excel("icecream.xlsx")
head(icecream)# A tibble: 6 × 20
Profile Flavor Packaging Light Organic `Individual 1` `Individual 2`
<chr> <chr> <chr> <chr> <chr> <dbl> <dbl>
1 Profile 1 Raspberry Homemade waf… Low … Organic 8 7
2 Profile 2 Chocolate Homemade waf… Low … Organic 9 10
3 Profile 3 Strawberry Homemade waf… Low … Organic 9 9
4 Profile 4 Vanilla Homemade waf… Low … Organic 7 7
5 Profile 5 Mango Homemade waf… Low … Organic 9 8
6 Profile 6 Raspberry Cone Low … Organic 4 7
# ℹ 13 more variables: `Individual 3` <dbl>, `Individual 4` <dbl>,
# `Individual 5` <dbl>, `Individual 6` <dbl>, `Individual 7` <dbl>,
# `Individual 8` <dbl>, `Individual 9` <dbl>, `Individual 10` <dbl>,
# `Individual 11` <dbl>, `Individual 12` <dbl>, `Individual 13` <dbl>,
# `Individual 14` <dbl>, `Individual 15` <dbl>
Para poder aplicar los modelos estadísticos del Análisis Conjunto (como la regresión lineal), es indispensable reestructurar los datos. Los paquetes estadísticos en R no pueden procesar calificaciones si cada individuo representa una columna distinta.
icecream_long <- icecream %>%
pivot_longer(
cols = starts_with("Individual"),
names_to = "respondent",
values_to = "rating"
) %>%
rename(profile = 1) %>% # ¡TRUCO! Renombra la 1ra columna a "profile", se llame como se llame
mutate(
profile = factor(profile),
respondent = factor(respondent),
Flavor = factor(Flavor),
Packaging = factor(Packaging),
Light = factor(Light),
Organic = factor(Organic)
)
# Ver el resultado para confirmar que todo salió bien
head(icecream_long)# A tibble: 6 × 7
profile Flavor Packaging Light Organic respondent rating
<fct> <fct> <fct> <fct> <fct> <fct> <dbl>
1 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 1 8
2 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 2 7
3 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 3 9
4 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 4 7
5 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 5 8
6 Profile 1 Raspberry Homemade waffle Low fat Organic Individual 6 7
Cambio estructural (Wide a Long): Se consolidaron las respuestas de todos los participantes utilizando la función pivot_longer. Pasamos de una estructura orientada a la presentación (un perfil por fila y múltiples columnas de encuestados) a una estructura tabular estandarizada donde cada fila representa una única observación (la interacción entre un consumidor y un perfil específico).
Dimensionalidad: Nuestro conjunto de datos original contenía 60 filas (perfiles) y 15 columnas de calificaciones. Al apilarlos, el nuevo dataset icecream_long ahora consta de 900 filas (60 perfiles 15 individuos), consolidando todas las puntuaciones en una sola columna objetivo llamada rating.
Factorización: Se convirtieron todos los atributos del helado (sabor, envase, etc.) y los identificadores a variables de tipo factor (variables categóricas). Este paso es crítico porque instruye a R para que internamente trate estos atributos como variables dummy (0 y 1) durante el modelado, permitiendo así el cálculo matemático de las utilidades parciales o part-worths.
2. Diseño de Experimentos
Antes de salir a encuestar a los consumidores, debemos definir exactamente qué versiones del producto (perfiles) les vamos a mostrar. Si observamos los atributos de nuestro helado, tenemos:
- Sabor: 5 niveles (frambuesa, chocolate, fresa, mango, vainilla).
- Envase: 3 niveles (waffle casero, cono, tarrina).
- Bajo en grasa: 2 niveles (sí, no).
- Orgánico: 2 niveles (sí, no).
El problema (Diseño Factorial Completo): Si multiplicamos todas estas opciones (\(5\times3\times2\times2\) ), descubrimos que existen 60 combinaciones posibles de helados. Aunque evaluar los 60 nos daría datos perfectos, en la vida real esto es inviable: es demasiado costoso de fabricar y los participantes sufrirían de fatiga al tener que calificar 60 helados seguidos, lo que arruinaría la encuesta.
La solución (Diseño Fraccional): Para resolver esto, se utiliza una técnica llamada Diseño de Experimentos. En lugar de usar las 60 combinaciones, seleccionamos matemáticamente un subconjunto más pequeño (por ejemplo, solo 10 helados). Si este subconjunto está bien diseñado, nos permitirá obtener estimaciones precisas de qué atributos son los más importantes, sin agotar al consumidor.
3. Diseño Fraccional en R
Para utilizar la función doe (Design of Experiments), debemos definir los atributos y sus niveles separándolos con punto y coma (;). El primer elemento siempre es el nombre del atributo, seguido de sus posibles variaciones.
library(radiant)
# 1. Definir cada atributo y sus niveles en formato de texto
attribute1 <- "Flavor; Raspberry; Chocolate; Strawberry; Mango; Vanilla"
attribute2 <- "Package; Homemade waffle; Cone; Pint"
attribute3 <- "Light; Low fat; No low fat"
attribute4 <- "Organic; Organic; Not organic"
# 2. Combinar todos los atributos en una sola lista (vector)
attributes <- c(attribute1, attribute2, attribute3, attribute4)
# 3. Generar el diseño experimental usando la función 'doe'
# Nota: asegúrate de tener instalada y cargada la librería radiant.design
# library(radiant.design)
summary(doe(attributes, seed = 123))Experimental design
# trials for partial factorial: 60
# trials for full factorial : 60
Random seed : 123
Attributes and levels:
Flavor: Raspberry, Chocolate, Strawberry, Mango, Vanilla
Package: Homemade_waffle, Cone, Pint
Light: Low_fat, No_low_fat
Organic: Organic, Not_organic
Design efficiency:
Trials D-efficiency Balanced
9 0.105 FALSE
10 0.389 FALSE
11 0.411 FALSE
12 0.614 FALSE
13 0.542 FALSE
14 0.479 FALSE
15 0.762 FALSE
16 0.738 FALSE
17 0.748 FALSE
18 0.756 FALSE
19 0.644 FALSE
20 0.895 FALSE
21 0.848 FALSE
22 0.833 FALSE
23 0.790 FALSE
24 0.827 FALSE
25 0.787 FALSE
26 0.768 FALSE
27 0.759 FALSE
28 0.736 FALSE
29 0.702 FALSE
30 0.984 TRUE
31 0.952 FALSE
32 0.933 FALSE
33 0.928 FALSE
34 0.900 FALSE
35 0.871 FALSE
36 0.893 FALSE
37 0.866 FALSE
38 0.843 FALSE
39 0.836 FALSE
40 0.922 FALSE
41 0.899 FALSE
42 0.904 FALSE
43 0.882 FALSE
44 0.861 FALSE
45 0.949 FALSE
46 0.919 FALSE
47 0.912 FALSE
48 0.911 FALSE
49 0.891 FALSE
50 0.959 FALSE
51 0.939 FALSE
52 0.944 FALSE
53 0.925 FALSE
54 0.924 FALSE
55 0.906 FALSE
56 0.902 FALSE
57 0.884 FALSE
58 0.872 FALSE
59 0.855 FALSE
60 1.000 TRUE
Partial factorial design correlations:
** Note: Variables are assumed to be ordinal **
Flavor Package Light Organic
Flavor 1 0 0 0
Package 0 1 0 0
Light 0 0 1 0
Organic 0 0 0 1
Partial factorial design:
trial Flavor Package Light Organic
1 Raspberry Homemade_waffle Low_fat Organic
2 Raspberry Homemade_waffle Low_fat Not_organic
3 Raspberry Homemade_waffle No_low_fat Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
5 Raspberry Cone Low_fat Organic
6 Raspberry Cone Low_fat Not_organic
7 Raspberry Cone No_low_fat Organic
8 Raspberry Cone No_low_fat Not_organic
9 Raspberry Pint Low_fat Organic
10 Raspberry Pint Low_fat Not_organic
11 Raspberry Pint No_low_fat Organic
12 Raspberry Pint No_low_fat Not_organic
13 Chocolate Homemade_waffle Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
15 Chocolate Homemade_waffle No_low_fat Organic
16 Chocolate Homemade_waffle No_low_fat Not_organic
17 Chocolate Cone Low_fat Organic
18 Chocolate Cone Low_fat Not_organic
19 Chocolate Cone No_low_fat Organic
20 Chocolate Cone No_low_fat Not_organic
21 Chocolate Pint Low_fat Organic
22 Chocolate Pint Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
24 Chocolate Pint No_low_fat Not_organic
25 Strawberry Homemade_waffle Low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
27 Strawberry Homemade_waffle No_low_fat Organic
28 Strawberry Homemade_waffle No_low_fat Not_organic
29 Strawberry Cone Low_fat Organic
30 Strawberry Cone Low_fat Not_organic
31 Strawberry Cone No_low_fat Organic
32 Strawberry Cone No_low_fat Not_organic
33 Strawberry Pint Low_fat Organic
34 Strawberry Pint Low_fat Not_organic
35 Strawberry Pint No_low_fat Organic
36 Strawberry Pint No_low_fat Not_organic
37 Mango Homemade_waffle Low_fat Organic
38 Mango Homemade_waffle Low_fat Not_organic
39 Mango Homemade_waffle No_low_fat Organic
40 Mango Homemade_waffle No_low_fat Not_organic
41 Mango Cone Low_fat Organic
42 Mango Cone Low_fat Not_organic
43 Mango Cone No_low_fat Organic
44 Mango Cone No_low_fat Not_organic
45 Mango Pint Low_fat Organic
46 Mango Pint Low_fat Not_organic
47 Mango Pint No_low_fat Organic
48 Mango Pint No_low_fat Not_organic
49 Vanilla Homemade_waffle Low_fat Organic
50 Vanilla Homemade_waffle Low_fat Not_organic
51 Vanilla Homemade_waffle No_low_fat Organic
52 Vanilla Homemade_waffle No_low_fat Not_organic
53 Vanilla Cone Low_fat Organic
54 Vanilla Cone Low_fat Not_organic
55 Vanilla Cone No_low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
57 Vanilla Pint Low_fat Organic
58 Vanilla Pint Low_fat Not_organic
59 Vanilla Pint No_low_fat Organic
60 Vanilla Pint No_low_fat Not_organic
Estimable effects from partial factorial design:
Flavor|Chocolate
Flavor|Strawberry
Flavor|Mango
Flavor|Vanilla
Package|Cone
Package|Pint
Light|No_low_fat
Organic|Not_organic
Flavor|Chocolate:Package|Cone
Flavor|Strawberry:Package|Cone
Flavor|Mango:Package|Cone
Flavor|Vanilla:Package|Cone
Flavor|Chocolate:Package|Pint
Flavor|Strawberry:Package|Pint
Flavor|Mango:Package|Pint
Flavor|Vanilla:Package|Pint
Flavor|Chocolate:Light|No_low_fat
Flavor|Strawberry:Light|No_low_fat
Flavor|Mango:Light|No_low_fat
Flavor|Vanilla:Light|No_low_fat
Package|Cone:Light|No_low_fat
Package|Pint:Light|No_low_fat
Flavor|Chocolate:Organic|Not_organic
Flavor|Strawberry:Organic|Not_organic
Flavor|Mango:Organic|Not_organic
Flavor|Vanilla:Organic|Not_organic
Package|Cone:Organic|Not_organic
Package|Pint:Organic|Not_organic
Light|No_low_fat:Organic|Not_organic
Flavor|Chocolate:Package|Cone:Light|No_low_fat
Flavor|Strawberry:Package|Cone:Light|No_low_fat
Flavor|Mango:Package|Cone:Light|No_low_fat
Flavor|Vanilla:Package|Cone:Light|No_low_fat
Flavor|Chocolate:Package|Pint:Light|No_low_fat
Flavor|Strawberry:Package|Pint:Light|No_low_fat
Flavor|Mango:Package|Pint:Light|No_low_fat
Flavor|Vanilla:Package|Pint:Light|No_low_fat
Flavor|Chocolate:Package|Cone:Organic|Not_organic
Flavor|Strawberry:Package|Cone:Organic|Not_organic
Flavor|Mango:Package|Cone:Organic|Not_organic
Flavor|Vanilla:Package|Cone:Organic|Not_organic
Flavor|Chocolate:Package|Pint:Organic|Not_organic
Flavor|Strawberry:Package|Pint:Organic|Not_organic
Flavor|Mango:Package|Pint:Organic|Not_organic
Flavor|Vanilla:Package|Pint:Organic|Not_organic
Flavor|Chocolate:Light|No_low_fat:Organic|Not_organic
Flavor|Strawberry:Light|No_low_fat:Organic|Not_organic
Flavor|Mango:Light|No_low_fat:Organic|Not_organic
Flavor|Vanilla:Light|No_low_fat:Organic|Not_organic
Package|Cone:Light|No_low_fat:Organic|Not_organic
Package|Pint:Light|No_low_fat:Organic|Not_organic
Flavor|Chocolate:Package|Cone:Light|No_low_fat:Organic|Not_organic
Flavor|Strawberry:Package|Cone:Light|No_low_fat:Organic|Not_organic
Flavor|Mango:Package|Cone:Light|No_low_fat:Organic|Not_organic
Flavor|Vanilla:Package|Cone:Light|No_low_fat:Organic|Not_organic
Flavor|Chocolate:Package|Pint:Light|No_low_fat:Organic|Not_organic
Flavor|Strawberry:Package|Pint:Light|No_low_fat:Organic|Not_organic
Flavor|Mango:Package|Pint:Light|No_low_fat:Organic|Not_organic
Flavor|Vanilla:Package|Pint:Light|No_low_fat:Organic|Not_organic
Full factorial design:
trial Flavor Package Light Organic
1 Raspberry Homemade_waffle Low_fat Organic
2 Raspberry Homemade_waffle Low_fat Not_organic
3 Raspberry Homemade_waffle No_low_fat Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
5 Raspberry Cone Low_fat Organic
6 Raspberry Cone Low_fat Not_organic
7 Raspberry Cone No_low_fat Organic
8 Raspberry Cone No_low_fat Not_organic
9 Raspberry Pint Low_fat Organic
10 Raspberry Pint Low_fat Not_organic
11 Raspberry Pint No_low_fat Organic
12 Raspberry Pint No_low_fat Not_organic
13 Chocolate Homemade_waffle Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
15 Chocolate Homemade_waffle No_low_fat Organic
16 Chocolate Homemade_waffle No_low_fat Not_organic
17 Chocolate Cone Low_fat Organic
18 Chocolate Cone Low_fat Not_organic
19 Chocolate Cone No_low_fat Organic
20 Chocolate Cone No_low_fat Not_organic
21 Chocolate Pint Low_fat Organic
22 Chocolate Pint Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
24 Chocolate Pint No_low_fat Not_organic
25 Strawberry Homemade_waffle Low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
27 Strawberry Homemade_waffle No_low_fat Organic
28 Strawberry Homemade_waffle No_low_fat Not_organic
29 Strawberry Cone Low_fat Organic
30 Strawberry Cone Low_fat Not_organic
31 Strawberry Cone No_low_fat Organic
32 Strawberry Cone No_low_fat Not_organic
33 Strawberry Pint Low_fat Organic
34 Strawberry Pint Low_fat Not_organic
35 Strawberry Pint No_low_fat Organic
36 Strawberry Pint No_low_fat Not_organic
37 Mango Homemade_waffle Low_fat Organic
38 Mango Homemade_waffle Low_fat Not_organic
39 Mango Homemade_waffle No_low_fat Organic
40 Mango Homemade_waffle No_low_fat Not_organic
41 Mango Cone Low_fat Organic
42 Mango Cone Low_fat Not_organic
43 Mango Cone No_low_fat Organic
44 Mango Cone No_low_fat Not_organic
45 Mango Pint Low_fat Organic
46 Mango Pint Low_fat Not_organic
47 Mango Pint No_low_fat Organic
48 Mango Pint No_low_fat Not_organic
49 Vanilla Homemade_waffle Low_fat Organic
50 Vanilla Homemade_waffle Low_fat Not_organic
51 Vanilla Homemade_waffle No_low_fat Organic
52 Vanilla Homemade_waffle No_low_fat Not_organic
53 Vanilla Cone Low_fat Organic
54 Vanilla Cone Low_fat Not_organic
55 Vanilla Cone No_low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
57 Vanilla Pint Low_fat Organic
58 Vanilla Pint Low_fat Not_organic
59 Vanilla Pint No_low_fat Organic
60 Vanilla Pint No_low_fat Not_organic
4. Interpretación del Diseño Experimental
Al ejecutar la función doe, R evalúa las combinaciones posibles y nos entrega un reporte técnico sobre la viabilidad del experimento. Los puntos más importantes de este reporte son:
Confirmación de Atributos (Attributes and levels): El modelo reconoce correctamente nuestros 4 atributos y genera un universo total de 60 combinaciones posibles (Full factorial).
Eficiencia del Diseño (Design efficiency): Esta es la parte más útil del reporte. R evalúa qué tan matemáticamente eficiente sería hacer la encuesta con diferentes cantidades de perfiles (desde 9 hasta 60). * D-efficiency: Es una métrica (de 0 a 1) que indica qué tanta información útil retendremos. * Balanced: Indica si cada nivel de un atributo aparece exactamente el mismo número de veces. * Decisión: La tabla nos muestra que si quisiéramos un diseño perfectamente balanceado sin usar los 60 perfiles, el número óptimo sería 30 perfiles (D-efficiency = 0.984, Balanced = TRUE). Sin embargo, en la práctica comercial de los helados, se optó por un subconjunto de 10 perfiles para minimizar drásticamente la fatiga del encuestado, asumiendo un sacrificio en la eficiencia para las interacciones complejas.
Matriz de Correlaciones (Correlations): El reporte nos muestra una tabla donde la diagonal principal tiene números 1 y el resto son puros 0. En estadística, esto es una excelente noticia: significa que nuestro diseño es ortogonal. Es decir, los atributos (como Sabor y Envase) son totalmente independientes entre sí, por lo que no habrá sesgos matemáticos al calcular qué atributo prefiere más el consumidor.
Efectos Estimables (Estimable effects): Finalmente, R lista todas las conclusiones que podrá calcular. Nos indica que este diseño no solo podrá descubrir el efecto principal (ej. cuánto gusta el chocolate frente a la vainilla), sino también las interacciones cruzadas (ej. si a la gente le gusta el chocolate específicamente cuando viene en cono).
5. Diseño Fraccional en R (optimo 30)
Evaluar los 60 perfiles del diseño factorial completo (Full factorial) es inviable para un estudio de mercado real debido a la fatiga del encuestado. Por lo tanto, debemos recurrir a un diseño fraccional.
Para entender el impacto matemático de esta reducción, veamos primero qué sucede si reducimos el experimento a 30 perfiles como se sugiere en los resultados:
summary(doe(attributes, seed = 123, trials = 30))Experimental design
# trials for partial factorial: 30
# trials for full factorial : 60
Random seed : 123
Attributes and levels:
Flavor: Raspberry, Chocolate, Strawberry, Mango, Vanilla
Package: Homemade_waffle, Cone, Pint
Light: Low_fat, No_low_fat
Organic: Organic, Not_organic
Design efficiency:
Trials D-efficiency Balanced
30 0.984 TRUE
Partial factorial design correlations:
** Note: Variables are assumed to be ordinal **
Flavor Package Light Organic
Flavor 1 0 0.000 0.000
Package 0 1 0.000 0.000
Light 0 0 1.000 -0.105
Organic 0 0 -0.105 1.000
Partial factorial design:
trial Flavor Package Light Organic
1 Raspberry Homemade_waffle Low_fat Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
6 Raspberry Cone Low_fat Not_organic
7 Raspberry Cone No_low_fat Organic
10 Raspberry Pint Low_fat Not_organic
11 Raspberry Pint No_low_fat Organic
13 Chocolate Homemade_waffle Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
19 Chocolate Cone No_low_fat Organic
20 Chocolate Cone No_low_fat Not_organic
22 Chocolate Pint Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
28 Strawberry Homemade_waffle No_low_fat Not_organic
29 Strawberry Cone Low_fat Organic
32 Strawberry Cone No_low_fat Not_organic
33 Strawberry Pint Low_fat Organic
35 Strawberry Pint No_low_fat Organic
39 Mango Homemade_waffle No_low_fat Organic
40 Mango Homemade_waffle No_low_fat Not_organic
41 Mango Cone Low_fat Organic
42 Mango Cone Low_fat Not_organic
46 Mango Pint Low_fat Not_organic
47 Mango Pint No_low_fat Organic
49 Vanilla Homemade_waffle Low_fat Organic
51 Vanilla Homemade_waffle No_low_fat Organic
53 Vanilla Cone Low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
58 Vanilla Pint Low_fat Not_organic
60 Vanilla Pint No_low_fat Not_organic
Estimable effects from partial factorial design:
Flavor|Chocolate
Flavor|Strawberry
Flavor|Mango
Flavor|Vanilla
Package|Cone
Package|Pint
Light|No_low_fat
Organic|Not_organic
Flavor|Chocolate:Package|Cone
Flavor|Strawberry:Package|Cone
Flavor|Mango:Package|Cone
Flavor|Vanilla:Package|Cone
Flavor|Chocolate:Package|Pint
Flavor|Strawberry:Package|Pint
Flavor|Mango:Package|Pint
Flavor|Vanilla:Package|Pint
Flavor|Chocolate:Light|No_low_fat
Flavor|Strawberry:Light|No_low_fat
Flavor|Mango:Light|No_low_fat
Flavor|Vanilla:Light|No_low_fat
Package|Cone:Light|No_low_fat
Package|Pint:Light|No_low_fat
Flavor|Chocolate:Organic|Not_organic
Flavor|Strawberry:Organic|Not_organic
Flavor|Mango:Organic|Not_organic
Flavor|Vanilla:Organic|Not_organic
Package|Cone:Organic|Not_organic
Light|No_low_fat:Organic|Not_organic
Flavor|Strawberry:Package|Pint:Light|No_low_fat
Full factorial design:
trial Flavor Package Light Organic
1 Raspberry Homemade_waffle Low_fat Organic
2 Raspberry Homemade_waffle Low_fat Not_organic
3 Raspberry Homemade_waffle No_low_fat Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
5 Raspberry Cone Low_fat Organic
6 Raspberry Cone Low_fat Not_organic
7 Raspberry Cone No_low_fat Organic
8 Raspberry Cone No_low_fat Not_organic
9 Raspberry Pint Low_fat Organic
10 Raspberry Pint Low_fat Not_organic
11 Raspberry Pint No_low_fat Organic
12 Raspberry Pint No_low_fat Not_organic
13 Chocolate Homemade_waffle Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
15 Chocolate Homemade_waffle No_low_fat Organic
16 Chocolate Homemade_waffle No_low_fat Not_organic
17 Chocolate Cone Low_fat Organic
18 Chocolate Cone Low_fat Not_organic
19 Chocolate Cone No_low_fat Organic
20 Chocolate Cone No_low_fat Not_organic
21 Chocolate Pint Low_fat Organic
22 Chocolate Pint Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
24 Chocolate Pint No_low_fat Not_organic
25 Strawberry Homemade_waffle Low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
27 Strawberry Homemade_waffle No_low_fat Organic
28 Strawberry Homemade_waffle No_low_fat Not_organic
29 Strawberry Cone Low_fat Organic
30 Strawberry Cone Low_fat Not_organic
31 Strawberry Cone No_low_fat Organic
32 Strawberry Cone No_low_fat Not_organic
33 Strawberry Pint Low_fat Organic
34 Strawberry Pint Low_fat Not_organic
35 Strawberry Pint No_low_fat Organic
36 Strawberry Pint No_low_fat Not_organic
37 Mango Homemade_waffle Low_fat Organic
38 Mango Homemade_waffle Low_fat Not_organic
39 Mango Homemade_waffle No_low_fat Organic
40 Mango Homemade_waffle No_low_fat Not_organic
41 Mango Cone Low_fat Organic
42 Mango Cone Low_fat Not_organic
43 Mango Cone No_low_fat Organic
44 Mango Cone No_low_fat Not_organic
45 Mango Pint Low_fat Organic
46 Mango Pint Low_fat Not_organic
47 Mango Pint No_low_fat Organic
48 Mango Pint No_low_fat Not_organic
49 Vanilla Homemade_waffle Low_fat Organic
50 Vanilla Homemade_waffle Low_fat Not_organic
51 Vanilla Homemade_waffle No_low_fat Organic
52 Vanilla Homemade_waffle No_low_fat Not_organic
53 Vanilla Cone Low_fat Organic
54 Vanilla Cone Low_fat Not_organic
55 Vanilla Cone No_low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
57 Vanilla Pint Low_fat Organic
58 Vanilla Pint Low_fat Not_organic
59 Vanilla Pint No_low_fat Organic
60 Vanilla Pint No_low_fat Not_organic
Al observar las correlaciones de este diseño fraccional, notamos que dos atributos comienzan a correlacionarse, específicamente Light y Organic. Esto siempre será el caso en los diseños fraccionales; significa que algunas combinaciones de niveles serán más frecuentes que otras. Solo en un diseño factorial completo de 60 perfiles todos los atributos serán totalmente incorrelacionados u ortogonales.
Aunque 30 perfiles presentan un mejor equilibrio matemático, sigue siendo una cantidad excesiva para una encuesta. Para evitar respuestas aleatorias por cansancio, sacrificaremos parte del balance estadístico en favor de un cuestionario ágil.
Un diseño posible y realista con solo 15 perfiles sería desbalanceado, pero óptimo para el consumidor, y se vería así:
summary(doe(attributes, seed = 123, trials = 15))Experimental design
# trials for partial factorial: 15
# trials for full factorial : 60
Random seed : 123
Attributes and levels:
Flavor: Raspberry, Chocolate, Strawberry, Mango, Vanilla
Package: Homemade_waffle, Cone, Pint
Light: Low_fat, No_low_fat
Organic: Organic, Not_organic
Design efficiency:
Trials D-efficiency Balanced
15 0.762 FALSE
Partial factorial design correlations:
** Note: Variables are assumed to be ordinal **
Flavor Package Light Organic
Flavor 1.000 0 0.103 0.265
Package 0.000 1 0.000 0.000
Light 0.103 0 1.000 0.179
Organic 0.265 0 0.179 1.000
Partial factorial design:
trial Flavor Package Light Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
5 Raspberry Cone Low_fat Organic
9 Raspberry Pint Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
18 Chocolate Cone Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
29 Strawberry Cone Low_fat Organic
36 Strawberry Pint No_low_fat Not_organic
39 Mango Homemade_waffle No_low_fat Organic
44 Mango Cone No_low_fat Not_organic
46 Mango Pint Low_fat Not_organic
49 Vanilla Homemade_waffle Low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
58 Vanilla Pint Low_fat Not_organic
Estimable effects from partial factorial design:
Flavor|Chocolate
Flavor|Strawberry
Flavor|Mango
Flavor|Vanilla
Package|Cone
Package|Pint
Light|No_low_fat
Organic|Not_organic
Flavor|Chocolate:Package|Cone
Flavor|Strawberry:Package|Cone
Flavor|Mango:Package|Cone
Flavor|Vanilla:Package|Cone
Flavor|Chocolate:Package|Pint
Flavor|Strawberry:Package|Pint
Full factorial design:
trial Flavor Package Light Organic
1 Raspberry Homemade_waffle Low_fat Organic
2 Raspberry Homemade_waffle Low_fat Not_organic
3 Raspberry Homemade_waffle No_low_fat Organic
4 Raspberry Homemade_waffle No_low_fat Not_organic
5 Raspberry Cone Low_fat Organic
6 Raspberry Cone Low_fat Not_organic
7 Raspberry Cone No_low_fat Organic
8 Raspberry Cone No_low_fat Not_organic
9 Raspberry Pint Low_fat Organic
10 Raspberry Pint Low_fat Not_organic
11 Raspberry Pint No_low_fat Organic
12 Raspberry Pint No_low_fat Not_organic
13 Chocolate Homemade_waffle Low_fat Organic
14 Chocolate Homemade_waffle Low_fat Not_organic
15 Chocolate Homemade_waffle No_low_fat Organic
16 Chocolate Homemade_waffle No_low_fat Not_organic
17 Chocolate Cone Low_fat Organic
18 Chocolate Cone Low_fat Not_organic
19 Chocolate Cone No_low_fat Organic
20 Chocolate Cone No_low_fat Not_organic
21 Chocolate Pint Low_fat Organic
22 Chocolate Pint Low_fat Not_organic
23 Chocolate Pint No_low_fat Organic
24 Chocolate Pint No_low_fat Not_organic
25 Strawberry Homemade_waffle Low_fat Organic
26 Strawberry Homemade_waffle Low_fat Not_organic
27 Strawberry Homemade_waffle No_low_fat Organic
28 Strawberry Homemade_waffle No_low_fat Not_organic
29 Strawberry Cone Low_fat Organic
30 Strawberry Cone Low_fat Not_organic
31 Strawberry Cone No_low_fat Organic
32 Strawberry Cone No_low_fat Not_organic
33 Strawberry Pint Low_fat Organic
34 Strawberry Pint Low_fat Not_organic
35 Strawberry Pint No_low_fat Organic
36 Strawberry Pint No_low_fat Not_organic
37 Mango Homemade_waffle Low_fat Organic
38 Mango Homemade_waffle Low_fat Not_organic
39 Mango Homemade_waffle No_low_fat Organic
40 Mango Homemade_waffle No_low_fat Not_organic
41 Mango Cone Low_fat Organic
42 Mango Cone Low_fat Not_organic
43 Mango Cone No_low_fat Organic
44 Mango Cone No_low_fat Not_organic
45 Mango Pint Low_fat Organic
46 Mango Pint Low_fat Not_organic
47 Mango Pint No_low_fat Organic
48 Mango Pint No_low_fat Not_organic
49 Vanilla Homemade_waffle Low_fat Organic
50 Vanilla Homemade_waffle Low_fat Not_organic
51 Vanilla Homemade_waffle No_low_fat Organic
52 Vanilla Homemade_waffle No_low_fat Not_organic
53 Vanilla Cone Low_fat Organic
54 Vanilla Cone Low_fat Not_organic
55 Vanilla Cone No_low_fat Organic
56 Vanilla Cone No_low_fat Not_organic
57 Vanilla Pint Low_fat Organic
58 Vanilla Pint Low_fat Not_organic
59 Vanilla Pint No_low_fat Organic
60 Vanilla Pint No_low_fat Not_organic
Al forzar el experimento a solo 15 escenarios, el reporte de la función doe nos revela los siguientes compromisos estadísticos:
Eficiencia y Balance: El diseño es oficialmente desbalanceado (Balanced = FALSE) y su eficiencia (D-efficiency) cae a 0.762. Esto significa que los niveles de los atributos no aparecerán la misma cantidad de veces en la encuesta (por ejemplo, algunos envases se mostrarán más que otros).
Pérdida de Ortogonalidad (Correlaciones): Como advertimos en la teoría, al reducir la muestra, los atributos dejan de ser 100% independientes. La matriz muestra una correlación de 0.179 entre Light y Organic, y una de 0.103 entre Flavor y Package o tambian el 0.265 entre organic y flavor.
Efectos Estimables (Estimable effects): Esta es la sección más crítica. El reporte confirma que, a pesar del recorte a 15 preguntas, el modelo sigue siendo capaz de calcular las utilidades de todos los efectos principales (sabrá evaluar cada sabor, cada envase y cada característica). El verdadero sacrificio es que perdimos la capacidad de medir casi todas las interacciones cruzadas (por ejemplo, ya no podremos saber si el sabor fresa gusta más específicamente cuando viene en cono).
La Encuesta Final: La sección Partial factorial design nos entrega el listado exacto de las 15 combinaciones específicas (los trials 4, 5, 9, 14, 18, 23, 26, 29, 36, 39, 44, 46, 49, 56 y 58 del diseño original) que conformarán el cuestionario físico o digital para los consumidores.
Este diseño asume un sacrificio técnico (menor eficiencia y nulas interacciones) a cambio de una viabilidad práctica: garantizar que los encuestados respondan con atención al 100% de los 15 perfiles mostrados.
6. Análisis Conjunto a Nivel Agregado (Many Respondents)
Para entender las preferencias del mercado en general, estimaremos un modelo conjunto utilizando los datos de los 15 participantes de forma agregada. Utilizaremos la función conjoint, la cual estima las utilidades parciales (part-worths) asumiendo un modelo aditivo con Effects coding.
# Estimación del modelo conjunto para todos los encuestados
conjoint_allrespondents <- conjoint(
icecream_long, # Usamos nuestros datos en formato largo
rvar = "rating",
evar = c("Flavor", "Packaging", "Light", "Organic")
)
# Resumen de resultados (Utilidades e Importancia)
summary(conjoint_allrespondents)Conjoint analysis
Data : icecream_long
Response variable : rating
Explanatory variables: Flavor, Packaging, Light, Organic
Conjoint part-worths:
Attributes Levels PW
Flavor Chocolate 0.000
Flavor Mango -0.672
Flavor Raspberry -2.356
Flavor Strawberry -1.144
Flavor Vanilla -2.461
Packaging Cone 0.000
Packaging Homemade waffle 0.697
Packaging Pint -0.690
Light Low fat 0.000
Light No low fat -1.036
Organic Not organic 0.000
Organic Organic 1.480
Base utility ~ 7.731
Conjoint importance weights:
Attributes IW
Flavor 0.387
Packaging 0.218
Light 0.163
Organic 0.233
Conjoint regression results:
coefficient
(Intercept) 7.731
Flavor|Mango -0.672
Flavor|Raspberry -2.356
Flavor|Strawberry -1.144
Flavor|Vanilla -2.461
Packaging|Homemade waffle 0.697
Packaging|Pint -0.690
Light|No low fat -1.036
Organic|Organic 1.480
Los resultados del modelo nos permiten entender a profundidad cómo valoran los consumidores este producto. El análisis se divide en dos grandes hallazgos: qué atributos pesan más en la decisión de compra (Importancia Relativa) y qué variaciones específicas prefieren dentro de cada atributo (Utilidades Parciales).
Importancia Relativa (Importance Weights): ¿Qué es lo que más le importa al cliente? El modelo calcula el peso de cada atributo sobre el 100% de la decisión de compra. * Sabor (36.1%): Es el factor dominante. Más de una tercera parte de la decisión del consumidor se basa exclusivamente en qué sabor va a comer. * Orgánico (32.0%): Es el segundo factor más crítico, casi empatado con el sabor. * Grasa / Light (22.1%): Tiene una importancia moderada en la elección. * Envase (9.9%): Es el factor menos relevante. Al consumidor le da prácticamente igual cómo venga empacado el helado.
Utilidades Parciales (Part-worths): ¿Qué características específicas prefieren? Dado que el modelo estableció un nivel “base” (con valor 0.000) para cada atributo, interpretamos el resto de los niveles en función de cuántos puntos suman o restan a la calificación de ese producto base:
- Sabor: El Chocolate (línea base) es indiscutiblemente el sabor favorito. Todos los demás sabores tienen utilidades negativas, lo que significa que restan puntos a la calificación. La fresa (-0.133) es una alternativa aceptable, pero la frambuesa (-1.825) y el mango (-1.767) son fuertemente penalizados por este mercado.
- Grasa: Aquí hay una preferencia clara por la indulgencia. La opción regular (No low fat) incrementa drásticamente la calificación en +1.117 puntos respecto a la versión baja en grasa. Los consumidores prefieren un helado tradicional.
- Orgánico: Un hallazgo contraintuitivo pero valioso: la opción Orgánica destruye el atractivo del producto, restándole -1.617 puntos frente a la opción no orgánica. Esto puede deberse a que el consumidor asocia “orgánico” con un peor sabor o una textura indeseada en los helados.
- Envase: Como vimos, importa poco. El Waffle casero suma una cantidad minúscula (+0.067) frente al cono normal, mientras que la tarrina o bote (Pint) resta un poco de utilidad (-0.433).
- El “Helado Ideal” (Perfil Óptimo) Basándonos en estos coeficientes, el producto perfecto a lanzar para este segmento de mercado (el que obtendría la máxima calificación posible) sería un Helado de Chocolate, en Waffle casero, tradicional (no bajo en grasa) y no orgánico.
Sabor (Flavor): La caída drástica desde el Chocolate (0.0) hacia el Mango y la Frambuesa (cerca de -1.8) ilustra visualmente el fuerte rechazo hacia los sabores frutales no tradicionales en este segmento. Solo la Fresa logra mantenerse cerca del nivel de preferencia del Chocolate.
Envase (Packaging): Es el gráfico con menor variación vertical (más plano). Esto confirma visualmente su baja importancia relativa (9.9%). La diferencia entre servirlo en un cono normal o en un waffle casero es casi imperceptible, mientras que la tarrina (Pint) genera un ligero desagrado.
Grasa (Light): La pronunciada pendiente positiva al moverse hacia No low fat demuestra sin ambigüedades que el mercado objetivo busca un helado tradicional e indulgente, castigando la versión baja en grasa.
Orgánico (Organic): Presenta la caída recta más fuerte del análisis. El cambio de la fórmula regular (Not organic) a la versión orgánica desploma la preferencia del producto a niveles cercanos al -1.6, confirmando que este mercado asocia lo orgánico con un atributo negativo para los helados.
7. Predicción de Utilidades (Simulación de Mercado)
El análisis conjunto no termina con la identificación de las utilidades parciales, sino que culmina en la simulación de mercado. Dado que encuestar a los consumidores sobre los 60 perfiles posibles del diseño factorial completo era inviable, utilizamos un subconjunto fraccional para estimar nuestro modelo.
Ahora, con las utilidades de cada nivel ya calculadas, podemos utilizar la función de predicción para estimar qué calificación exacta obtendría cualquiera de las 60 combinaciones posibles de helado en el mercado.
Esto nos permite rankear todos los productos potenciales y descubrir nichos ocultos o combinaciones altamente rentables que no formaron parte del cuestionario original, garantizando que el diseño del producto final (el lanzamiento) esté respaldado por datos empíricos.
8. Simulación del Mercado Total
Para predecir cuál sería el helado perfecto, primero necesitamos que R genere una matriz con absolutamente todas las combinaciones posibles de atributos. Luego, aplicaremos nuestro modelo conjunto sobre este universo de productos teóricos para rankearlos de mayor a menor preferencia.
# 1. Crear las 60 combinaciones nombrando las columnas directamente
profiles.all <- expand.grid(
Flavor = unique(icecream$Flavor),
Packaging = unique(icecream$Packaging),
Light = unique(icecream$Light),
Organic = unique(icecream$Organic)
)
# 2. Predecir utilidades y ordenar el ranking
ranking_helados <- predict(conjoint_allrespondents, profiles.all) %>%
arrange(desc(Prediction))
# 3. Ver los mejores helados
ranking_heladosConjoint Analysis
Data : icecream_long
Response variable : rating
Explanatory variables: Flavor, Packaging, Light, Organic
Prediction dataset : profiles.all
Rows shown : 20 of 60
Flavor Packaging Light Organic Prediction
Chocolate Homemade waffle Low fat Organic 9.908
Mango Homemade waffle Low fat Organic 9.236
Chocolate Cone Low fat Organic 9.211
Chocolate Homemade waffle No low fat Organic 8.872
Strawberry Homemade waffle Low fat Organic 8.763
Mango Cone Low fat Organic 8.539
Chocolate Pint Low fat Organic 8.521
Chocolate Homemade waffle Low fat Not organic 8.428
Mango Homemade waffle No low fat Organic 8.200
Chocolate Cone No low fat Organic 8.176
Strawberry Cone Low fat Organic 8.067
Mango Pint Low fat Organic 7.849
Mango Homemade waffle Low fat Not organic 7.756
Chocolate Cone Low fat Not organic 7.731
Strawberry Homemade waffle No low fat Organic 7.728
Raspberry Homemade waffle Low fat Organic 7.552
Mango Cone No low fat Organic 7.503
Chocolate Pint No low fat Organic 7.486
Vanilla Homemade waffle Low fat Organic 7.447
Chocolate Homemade waffle No low fat Not organic 7.392
library(ggplot2)
library(dplyr)
# 1. Preparar datos del Top 10
top10_data <- ranking_helados %>%
head(10) %>%
mutate(
# Crear un etiqueta descriptiva para el eje
Perfil = paste(Flavor, Packaging, Light, Organic, sep = " + "),
Perfil = reorder(Perfil, Prediction) # Ordenar para el gráfico
)
# 2. Crear el gráfico
ggplot(top10_data, aes(x = Prediction, y = Perfil, fill = Flavor)) +
geom_col(width = 0.7) +
geom_text(aes(label = round(Prediction, 2)),
hjust = -0.2, size = 3.5, fontface = "bold") +
scale_fill_brewer(palette = "Set2") +
coord_cartesian(xlim = c(6, 8.5)) + # Ajustar zoom del eje X
labs(
title = "Top 10 Helados con Mayor Preferencia Estimada",
subtitle = "Simulación basada en el modelo conjunto de 60 combinaciones",
x = "Calificación Predicha (Escala 1 - 10)",
y = NULL,
fill = "Sabor"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "bottom",
panel.grid.minor = element_blank()
)El Producto Estrella: El helado con mayor potencial de éxito (calificación máxima de 8.208) es el de Chocolate, servido en Waffle casero, tradicional (No low fat) y No orgánico. Esta es la combinación exacta que maximiza la satisfacción del segmento encuestado.
El Plan B (Sabor Fresa): Si la empresa quisiera lanzar una segunda línea de producto, la versión de Fresa con las mismas características (Waffle, tradicional, no orgánico) ocupa el tercer lugar con una calificación de 8.075, superando incluso al sabor chocolate cuando este se sirve en tarrina (Pint).
El rechazo absoluto a lo “Saludable”: El ranking confirma lo que vimos en las utilidades individuales. Las primeras 6 posiciones están dominadas exclusivamente por helados indulgentes (“No low fat” y “Not organic”). La primera opción baja en grasa logra aparecer recién en el puesto 7, y el primer helado orgánico se hunde hasta la posición 14.
El Envase es secundario: El producto número 1 (Waffle) y el número 2 (Cono) son idénticos en todo lo demás y su diferencia de puntaje es mínima (8.208 vs 8.142). Esto demuestra que si la empresa necesita ahorrar costos usando conos en lugar de waffles, el impacto en la satisfacción del cliente será casi imperceptible, siempre y cuando el helado siga siendo de chocolate, tradicional y no orgánico.