Sobre este documento Este R Markdown corresponde al Script 1 del pipeline POGIT aplicado a la marca Adidas. Está basado directamente en el
code1.Rentregado por la directora de tesis (caso Apple). El script carga el survey de participantes del panel Amazon, construye las variables dummy de raza y eventos de vida, e integra todo en un objetosurvey_enrichedque será consumido por el Script 2.Modificaciones respecto a
code1.R(Apple):
Etiqueta Bloque Descripción MOD-01 Bloque 9 Nombre del PDF de salida cambiado a survey_barplots_adidas.pdfTodos los demás bloques son idénticos al original porque el survey es el mismo para Apple y para Adidas: los mismos participantes, las mismas preguntas demográficas.
Antes de ejecutar cualquier análisis, R necesita cargar las
librerías que contienen las funciones especializadas
del pipeline. Este bloque define el listado completo de paquetes y los
carga mediante una función personalizada load_pkg(), que
verifica que todos hayan sido instalados correctamente.
La razón de centralizar la carga aquí es que si algún paquete falta,
el error aparece desde el inicio y no a mitad del análisis. Los paquetes
cubren cuatro grandes áreas: manipulación de datos
(tidyverse, janitor, lubridate),
visualización (ggplot2,
scales, patchwork),
modelación (pscl, tidymodels,
caret) y cómputo paralelo
(parallel, furrr, optimParallel),
este último necesario para la estimación del modelo POGIT en el Script
3.
vapply(): Versión segura de
sapply(). Aplica una función a cada elemento y garantiza
que el resultado sea del tipo especificado (aquí logical).
Falla explícitamente si el tipo no coincide, lo que lo hace más robusto
en producción.suppressPackageStartupMessages():
Silencia los mensajes de bienvenida que algunos paquetes muestran al
cargarse. No afecta el funcionamiento.require(): Similar a
library() pero devuelve TRUE o
FALSE en lugar de lanzar un error si el paquete no existe.
Esto permite que load_pkg() capture el fallo y genere un
mensaje más informativo.optimParallel: Versión paralela del
optimizador optim() de R base. Se usa en el Script 3 para
la estimación por Máxima Verosimilitud (MLE) del modelo POGIT,
distribuyendo el cómputo en múltiples núcleos del procesador.numDeriv: Paquete para cálculo
numérico de derivadas. Se usa para obtener los errores estándar de los
coeficientes del modelo POGIT a partir de la matriz Hessiana de la
función de log-verosimilitud.packages <- unique(c(
"tidyverse", "lubridate", "janitor", "skimr", "snakecase",
"stringr", "dplyr", "gridExtra", "scales", "viridis",
"patchwork", "fastDummies", "readxl", "openxlsx", "tidymodels",
"Matrix", "caret", "pscl", "xgboost", "Metrics",
"numDeriv", "optimParallel", "parallel", "furrr", "progressr",
"tibble", "readr", "forcats", "ggplot2", "tidyr"
))
load_pkg <- function(pkgs) {
ok <- vapply(pkgs, function(p) {
suppressPackageStartupMessages(require(p, character.only = TRUE))
}, logical(1))
if (any(!ok)) {
stop("Packages not installed/loaded: ", paste(pkgs[!ok], collapse = ", "))
}
invisible(ok)
}
load_pkg(packages)Output esperado: Si todos los paquetes están instalados, este bloque no produce ningún mensaje visible. Si alguno falta, R arrojará un error indicando cuál paquete no pudo cargarse. Instalarlo con
install.packages("nombre_paquete")y reintentar.
Este bloque establece dos configuraciones globales: el
locale del sistema y la paleta de
colores. Ambas deben definirse antes de la función
bar_plot() del Bloque 3, porque bar_plot() usa
pal como valor por defecto de su argumento
fill_pal.
El locale (es_ES.UTF-8) configura R para interpretar
fechas, separadores y caracteres especiales en español. Si el sistema
operativo no lo soporta (común en Windows), R emite una advertencia pero
continúa sin interrumpirse.
La paleta pal es un vector nombrado de 10 colores en
formato hexadecimal seleccionados de la paleta Tableau, diseñada para
ser distinguible tanto en pantalla como en impresión en escala de
grises. Definirla como objeto global garantiza que todos los gráficos
del pipeline compartan el mismo esquema visual, y su posición antes de
bar_plot() es crítica porque la función la recibe como
argumento por defecto.
Sys.setlocale().identical(loc_ok, ""): Verifica si la
asignación del locale falló. Sys.setlocale() devuelve una
cadena vacía cuando no puede aplicar el locale. identical()
es más estricto que == porque también verifica el tipo de
dato.pal["azul_1"]). Permite referenciar
colores por nombre en lugar de por posición.#RRGGBB):
Representación de colores en base 16. Por ejemplo, #4E79A7
es un azul medio.loc_ok <- base::Sys.setlocale("LC_ALL", "es_ES.UTF-8")
if (identical(loc_ok, "")) {
warning(
"Could not set locale 'es_ES.UTF-8'; ",
"separators and month names will use the default locale."
)
}
pal <- c(
azul_1 = "#4E79A7",
naranja = "#F28E2B",
rojo = "#E15759",
turquesa = "#76B7B2",
verde = "#59A14F",
amarillo = "#EDC948",
morado = "#B07AA1",
rosa = "#FF9DA7",
cafe = "#9C755F",
gris = "#BAB0AC"
)Output esperado: Si el locale se configura correctamente, no aparece nada. En Windows es frecuente la advertencia de locale, pero el script continúa. El objeto
palqueda disponible en el entorno global con 10 colores nombrados.
bar_plot() y funciones auxiliaresEste bloque define la función bar_plot() y dos funciones
auxiliares de uso general en el pipeline: mode_safe() y
reorder_drop_id().
bar_plot() genera gráficas de barras
horizontales estandarizadas para cualquier variable
categórica del survey. Encapsula la lógica de visualización siguiendo el
principio DRY (Don’t Repeat Yourself): en
lugar de repetir el código 20 veces, una sola función recibe el
dataframe, la variable, los títulos y parámetros opcionales y produce el
gráfico. La función calcula frecuencias y porcentajes, ordena las barras
de mayor a menor con fct_reorder(), asigna colores
cíclicamente de la paleta, y usa coord_flip() para barras
horizontales que facilitan la lectura de etiquetas largas.
mode_safe() calcula la moda de un vector ignorando NAs.
Es “safe” porque no falla si el vector está vacío (devuelve
NA_character_). Se usará en el Script 2 para determinar el
estado de envío más frecuente por cliente.
reorder_drop_id() filtra un dataframe a un conjunto de
response_id y los reordena para coincidir exactamente con
el orden de referencia. Esta alineación exacta es crítica en el Script 2
cuando se construyen las matrices V y W.
{{ var }}: Operador embracing
de rlang. Permite que bar_plot() reciba el
nombre de una columna sin comillas y lo evalúe correctamente dentro de
dplyr. Es la sintaxis moderna para tidy
evaluation.forcats::fct_reorder(var_chr, n):
Reordena los niveles de un factor según otra variable (n =
frecuencia). Al combinarse con coord_flip(), produce barras
ordenadas de mayor a menor de arriba hacia abajo.coord_flip(): Invierte los ejes X e Y.
Convierte barras verticales en horizontales, facilitando la lectura de
etiquetas largas.rep(unname(fill_pal), length.out = nrow(counts)):
Repite los colores cíclicamente hasta tener exactamente tantos como
categorías. unname() elimina los nombres del vector para
evitar conflictos en scale_fill_manual().sprintf("%.1f%%", pct): Formatea el
porcentaje con un decimal y símbolo %. Produce cadenas como
“34.2%”.tabulate(match(x, ux)): Cuenta
frecuencias eficientemente. match() devuelve la posición de
cada elemento en el vector único; tabulate() cuenta cuántas
veces aparece cada posición.bar_plot <- function(df, var, title, x_lab,
fill_pal = pal, text_size = 3) {
counts <- df %>%
dplyr::filter(!is.na({{ var }})) %>%
dplyr::count({{ var }}, name = "n") %>%
dplyr::mutate(
pct = n / sum(n) * 100,
var_chr = as.character({{ var }})
) %>%
dplyr::arrange(dplyr::desc(n)) %>%
dplyr::mutate(var_chr = forcats::fct_reorder(var_chr, n))
fill_vals <- rep(unname(fill_pal), length.out = nrow(counts))
names(fill_vals) <- levels(counts$var_chr)
ggplot2::ggplot(counts, ggplot2::aes(x = var_chr, y = n, fill = var_chr)) +
ggplot2::geom_col() +
ggplot2::geom_text(
ggplot2::aes(label = sprintf("%.1f%%", pct), y = n),
hjust = -0.1, size = text_size, colour = "black"
) +
ggplot2::coord_flip() +
ggplot2::scale_y_continuous(
expand = ggplot2::expansion(mult = c(0, 0.15))
) +
ggplot2::scale_fill_manual(values = fill_vals, guide = "none") +
ggplot2::labs(title = title, x = x_lab, y = "Number of participants") +
ggplot2::theme_minimal()
}
mode_safe <- function(x) {
x <- x[!is.na(x) & x != ""]
if (length(x) == 0) return(NA_character_)
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
reorder_drop_id <- function(df, ref_ids) {
df %>%
dplyr::filter(response_id %in% ref_ids) %>%
dplyr::slice(match(ref_ids, response_id))
}Output esperado: Ningún output visible. Las tres funciones quedan registradas en el entorno global. Verificable con
exists("bar_plot"), que devolveráTRUE.
Este bloque carga el archivo principal de datos demográficos: el survey aplicado a los participantes del panel Amazon MTurk/Prolific. Es la fuente de todas las variables de control demográfico que entrarán al modelo como covariables: edad, género, nivel educativo, ingresos, tamaño del hogar, entre otras.
readr::read_csv() es más rápida que
read.csv() de R base para archivos grandes, maneja mejor la
codificación UTF-8, e infiere automáticamente los tipos de datos.
janitor::clean_names() estandariza todos los nombres de
columna a snake_case inmediatamente después de la carga,
evitando errores por mayúsculas o espacios en los nombres durante el
resto del pipeline.
El dataset contiene aproximadamente 5,027 participantes y es la fuente de todas las covariables declaradas por encuestado descritas en la Sección 3 del paper (Construction of Predictor Variables).
janitor::clean_names(): Convierte
nombres de columna a snake_case limpio. Ejemplo:
"Q_Demos_Age" → "q_demos_age".show_col_types = FALSE: Suprime el
mensaje informativo sobre tipos de dato inferidos. No afecta la
lectura.q_prolific_mturk
identifica la plataforma de origen de cada participante.survey <- readr::read_csv(
"data/survey-data/survey.csv",
show_col_types = FALSE
) %>%
janitor::clean_names()
message("Survey cargado: ", nrow(survey), " filas, ", ncol(survey), " columnas")## Survey cargado: 6325 filas, 41 columnas
Output esperado: Un mensaje del tipo
Survey cargado: 5027 filas, 41 columnas. Si aparece el errordoes not exist in current working directory, ajustar la ruta enknitr::opts_knit$set(root.dir = ...)del chunk de setup para que apunte a la carpeta donde existedata/survey-data/survey.csv.
La pregunta de raza en el survey es de selección
múltiple: un participante puede identificarse con varias razas
simultáneamente (ej: "Asian, White or Caucasian"). La
columna q_demos_race contiene cadenas de texto con
múltiples valores separados por coma, lo que impide aplicar one-hot
encoding directamente.
El pipeline de transformación sigue cinco pasos: normalización del
texto (espacios irregulares alrededor de separadores), expansión con
separate_rows() que convierte cada combinación en una fila
por raza (formato largo), asignación a uno de los 6 niveles oficiales
mediante factor con levels explícitos,
conversión a columnas binarias con pivot_wider() (una por
raza, prefijo race_), y verificación de que las 6 columnas
esperadas existen — creando con 0 las que no aparezcan en los datos.
Desde el punto de vista del modelo POGIT, las variables
race_* entran en la matriz V (covariables
de asignación del SoW). A diferencia de variables categóricas estándar,
estas dummies de raza no tienen categoría de referencia
eliminada porque son multi-selección: un participante puede
tener varios “1” simultáneos.
separate_rows(race_raw, sep = ",\\s*"):
Expande una columna con múltiples valores separados por coma en
múltiples filas. El patrón ",\\s*" matchea una coma seguida
de cero o más espacios. Transforma el formato multi-valor a formato
largo de una observación por fila.factor(race_raw, levels = race_levels):
Convierte la columna a factor con los 6 niveles oficiales predefinidos.
Cualquier valor que no coincida queda como NA. Garantiza
que solo se crean dummies para las 6 categorías del estudio.pivot_wider(names_prefix, values_fill = 0L):
Convierte formato largo a ancho, una columna por categoría.
values_fill = 0L asigna 0 a las combinaciones
participante-raza no presentes en los datos.janitor::make_clean_names(race_levels):
Convierte los nombres de los niveles de raza al mismo formato que
clean_names(). Se usa para construir los nombres esperados
de columnas y verificar que todas existen.race_dummies[setdiff(needed_race, names(race_dummies))] <- 0L:
Crea con valor 0 cualquier columna de raza que no aparezca en los datos.
Garantiza que el dataframe siempre tiene las 6 columnas esperadas.race_levels <- c(
"White or Caucasian",
"Black or African American",
"Asian",
"American Indian/Native American or Alaska Native",
"Native Hawaiian or Other Pacific Islander",
"Other"
)
race_long <- survey %>%
dplyr::select(response_id, race_raw = q_demos_race) %>%
dplyr::filter(!is.na(race_raw) & race_raw != "") %>%
dplyr::mutate(
race_raw = race_raw %>%
stringr::str_replace_all("\\s*/\\s*", "/") %>%
stringr::str_replace_all("\\s*,\\s*", ", ") %>%
stringr::str_squish()
) %>%
tidyr::separate_rows(race_raw, sep = ",\\s*") %>%
dplyr::mutate(race_raw = stringr::str_trim(race_raw))
race_dummies <- race_long %>%
dplyr::mutate(
race = factor(race_raw, levels = race_levels),
value = 1L
) %>%
dplyr::select(-race_raw) %>%
tidyr::pivot_wider(
names_from = race,
values_from = value,
names_prefix = "race_",
values_fill = 0L
) %>%
janitor::clean_names()
needed_race <- paste0("race_", janitor::make_clean_names(race_levels))
race_dummies[setdiff(needed_race, names(race_dummies))] <- 0L
message("race_dummies: ", ncol(race_dummies) - 1, " columnas | ",
nrow(race_dummies), " participantes con respuesta de raza")## race_dummies: 6 columnas | 6325 participantes con respuesta de raza
Output esperado: Mensaje con 6 columnas de raza y el número de participantes con respuesta válida. Las columnas serán:
race_white_or_caucasian,race_black_or_african_american,race_asian,race_other,race_american_indian_native_american_or_alaska_native,race_native_hawaiian_or_other_pacific_islander.
Este bloque aplica exactamente el mismo pipeline de transformación del Bloque 5, pero a la pregunta sobre cambios de vida en 2021: pérdida de empleo, mudanza, divorcio, nacimiento de un hijo, embarazo. Esta pregunta también es de selección múltiple.
La consistencia del procedimiento no es accidental: ambas preguntas
comparten la misma estructura multi-respuesta, por lo que el mismo
patrón (separate_rows → factor →
pivot_wider → clean_names → verificación)
aplica directamente. Esta consistencia también facilita la comprensión y
auditoría del código.
Desde el ángulo del modelo POGIT, las variables life_*
entran también en la matriz V como variables de
control: eventos de vida recientes pueden afectar el comportamiento de
compra de manera transitoria. La Sección 8 del paper reporta que
life_became_pregnant tiene efecto negativo significativo
sobre la intensidad de consumo en tecnología (λᵢ) — resultado que podría
replicarse o diferir en el caso de Adidas, siendo un hallazgo relevante
para comparar entre ambas marcas.
life_levels: Vector con los 5 niveles
oficiales de la pregunta de cambios de vida. Define los únicos valores
válidos que se convertirán en columnas dummy.needed_life: Vector con los nombres
esperados de las 5 columnas dummy de eventos de vida. Se usa para
verificar completitud y crear las faltantes con 0.life_levels <- c(
"Lost a job",
"Moved place of residence",
"Divorce",
"Had a child",
"Became pregnant"
)
life_long <- survey %>%
dplyr::select(response_id, life_raw = q_life_changes) %>%
dplyr::filter(!is.na(life_raw) & life_raw != "") %>%
dplyr::mutate(
life_raw = life_raw %>%
stringr::str_replace_all("\\s*/\\s*", "/") %>%
stringr::str_replace_all("\\s*,\\s*", ", ") %>%
stringr::str_squish()
) %>%
tidyr::separate_rows(life_raw, sep = ",\\s*") %>%
dplyr::mutate(life_raw = stringr::str_trim(life_raw))
life_dummies <- life_long %>%
dplyr::mutate(
life = factor(life_raw, levels = life_levels),
value = 1L
) %>%
dplyr::select(-life_raw) %>%
tidyr::pivot_wider(
names_from = life,
values_from = value,
names_prefix = "life_",
values_fill = 0L
) %>%
janitor::clean_names()
needed_life <- paste0("life_", janitor::make_clean_names(life_levels))
life_dummies[setdiff(needed_life, names(life_dummies))] <- 0L
message("life_dummies: ", ncol(life_dummies) - 1, " columnas | ",
nrow(life_dummies), " participantes con respuesta de cambios de vida")## life_dummies: 5 columnas | 2012 participantes con respuesta de cambios de vida
Output esperado: Mensaje con 5 columnas de eventos de vida y el número de participantes que declararon al menos un cambio. Las columnas serán:
life_lost_a_job,life_moved_place_of_residence,life_divorce,life_had_a_child,life_became_pregnant.
survey_enrichedEste bloque integra las variables dummy de raza y eventos de vida al
survey principal mediante left_join, creando el objeto
survey_enriched. Este es el entregable principal
del Script 1: el dataframe completo que será consumido por el
Script 2 para construir las matrices V y W.
Antes de cada join se aplica
distinct(response_id, .keep_all = TRUE) a los tres
dataframes para garantizar que no haya response_id
duplicados. El argumento relationship = "one-to-one" en
left_join() hace esta verificación explícita: si hubiera
duplicados, R lanzaría un error en lugar de continuar silenciosamente
con datos multiplicados.
El left_join desde survey (izquierda)
garantiza que todos los participantes del survey original estén en
survey_enriched, aunque no hayan respondido las preguntas
de raza o eventos de vida (en cuyo caso sus columnas race_*
y life_* serán NA). Estos NA se
manejarán en el Script 2.
distinct(response_id, .keep_all = TRUE):
Elimina filas duplicadas de response_id conservando la
primera ocurrencia de todas las columnas. Previene relaciones
many-to-many en los joins.relationship = "one-to-one":
Verificación explícita en left_join() de que la unión es
1:1. Si un response_id aparece más de una vez en alguno de
los dataframes, R lanza un error informativo.left_join(): Une dos dataframes
conservando todas las filas del izquierdo. Si un
response_id del survey no aparece en
race_dummies, las columnas de raza quedan como
NA.survey_enriched: Objeto final del
Script 1. Tiene las mismas filas que survey más las 11
columnas de dummies (6 de raza + 5 de vida). Es el input del Script
2.survey <- survey %>% dplyr::distinct(response_id, .keep_all = TRUE)
race_dummies <- race_dummies %>% dplyr::distinct(response_id, .keep_all = TRUE)
life_dummies <- life_dummies %>% dplyr::distinct(response_id, .keep_all = TRUE)
survey_enriched <- survey %>%
dplyr::left_join(race_dummies, by = "response_id",
relationship = "one-to-one") %>%
dplyr::left_join(life_dummies, by = "response_id",
relationship = "one-to-one")
message("survey_enriched: ", nrow(survey_enriched), " filas, ",
ncol(survey_enriched), " columnas")## survey_enriched: 6325 filas, 52 columnas
## [1] "duration_in_seconds"
## [2] "recorded_date"
## [3] "response_id"
## [4] "q_prolific_mturk"
## [5] "q_demos_age"
## [6] "q_demos_hispanic"
## [7] "q_demos_race"
## [8] "q_demos_education"
## [9] "q_demos_income"
## [10] "q_demos_gender"
## [11] "q_sexual_orientation"
## [12] "q_demos_state"
## [13] "q_amazon_use_howmany"
## [14] "q_amazon_use_hh_size"
## [15] "q_amazon_use_how_oft"
## [16] "q_substance_use_1"
## [17] "q_substance_use_2"
## [18] "q_substance_use_3"
## [19] "q_personal_1"
## [20] "q_personal_2"
## [21] "q_life_changes"
## [22] "q_control"
## [23] "q_altruism"
## [24] "q_bonus_05"
## [25] "q_bonus_20"
## [26] "q_bonus_50"
## [27] "q_data_value_05"
## [28] "q_data_value_20"
## [29] "q_data_value_50"
## [30] "q_data_value_100"
## [31] "q_data_value_any"
## [32] "q_data_value_any_1_text"
## [33] "q_sell_your_data"
## [34] "q_sell_consumer_data"
## [35] "q_small_biz_use"
## [36] "q_census_use"
## [37] "q_research_society"
## [38] "q_attn_check"
## [39] "showdata"
## [40] "incentive"
## [41] "connect"
## [42] "race_black_or_african_american"
## [43] "race_white_or_caucasian"
## [44] "race_asian"
## [45] "race_other"
## [46] "race_american_indian_native_american_or_alaska_native"
## [47] "race_native_hawaiian_or_other_pacific_islander"
## [48] "life_lost_a_job"
## [49] "life_moved_place_of_residence"
## [50] "life_divorce"
## [51] "life_had_a_child"
## [52] "life_became_pregnant"
Output esperado: Mensaje con dimensiones del objeto enriquecido (~5,027 filas, ~52 columnas) seguido de la lista completa de nombres de columna. Este output debe ser idéntico al que produce el
code1.Roriginal de Apple.
Este bloque genera los 20 gráficos de barras del survey llamando a
bar_plot() una vez por variable. Cada llamada produce un
objeto ggplot que se imprime directamente en el documento
HTML, permitiendo una exploración visual completa de la distribución de
la muestra.
La visualización del survey cumple una función metodológica importante: detectar variables con distribuciones muy desbalanceadas (>95% en una categoría) que podrían causar near-zero variance en el modelo, y verificar que la muestra tiene representación razonable en todos los grupos demográficos reportados en la Sección 2 del paper.
Se usan race_long y life_long (formato
largo, generados en los Bloques 5 y 6) para los gráficos de “conteo
individual”: esto permite ver la distribución de cada categoría por
separado, sin el ruido de las combinaciones multi-respuesta que contiene
q_demos_race y q_life_changes.
fill_pal = pal[c("azul_1", "naranja")]:
Para variables binarias (solo dos categorías), se pasan dos colores
contrastantes de la paleta. Produce gráficos más limpios que usar los 10
colores para dos barras.text_size = 2.8: Tamaño reducido de
las etiquetas para variables con muchas categorías (raza, educación,
estado) donde el tamaño por defecto causaría solapamiento.bar_plot(survey, q_demos_hispanic,
"Hispanic/Latino origin", "Response",
fill_pal = pal[c("azul_1", "naranja")])bar_plot(survey, q_life_changes,
"Life changes in 2021 (combinations)", "Combination",
text_size = 2.8)Output esperado: 20 gráficos de barras horizontales renderizados en el documento, uno por variable. Cada gráfico muestra barras ordenadas de mayor a menor con etiquetas de porcentaje. Este output es idéntico al que produce el
code1.Roriginal de Apple.
⚠️ MOD-01 — CAMBIO ADIDAS: El nombre del PDF cambia de
"survey_barplots.pdf"a"survey_barplots_adidas.pdf". Es la única modificación en todo el Script 1. El contenido es idéntico porque describe el mismo survey demográfico.
Este bloque almacena los 20 gráficos en la lista
plots_survey y los exporta a un único archivo PDF. La razón
de este doble paso — imprimir en pantalla en el Bloque 8, luego
construir la lista aquí — es que el Bloque 8 sirve para la visualización
interactiva en el Rmd, mientras que esta lista sirve exclusivamente para
la exportación al archivo PDF.
El flujo es: pdf() abre un dispositivo gráfico de
archivo, el for loop imprime cada gráfico con
print() explícito (necesario porque dentro de loops los
objetos ggplot no se imprimen automáticamente), y
dev.off() cierra el dispositivo y escribe el archivo en
disco.
pdf() redirige la salida gráfica a un archivo en
lugar de a la pantalla.grDevices::pdf(out_pdf, width = 10, height = 7):
Abre dispositivo gráfico PDF con dimensiones en pulgadas. Las
dimensiones 10×7 son adecuadas para barras horizontales.for (p in plots_survey) print(p):
Dentro de un loop, los objetos ggplot no se imprimen
automáticamente. print() explícito es necesario para
enviarlos al dispositivo activo.grDevices::dev.off(): Cierra el
dispositivo gráfico activo y finaliza la escritura del archivo. Sin este
paso, el PDF puede quedar corrupto o incompleto.plots_survey <- list(
bar_plot(survey, q_prolific_mturk,
"Participation in Amazon MTurk", "Response"),
bar_plot(survey, q_demos_age,
"Age group distribution", "Age group"),
bar_plot(survey, q_demos_hispanic,
"Hispanic/Latino origin", "Response",
fill_pal = pal[c("azul_1", "naranja")]),
bar_plot(survey, q_demos_race,
"Race combinations (declared)", "Combination",
text_size = 2.8),
bar_plot(race_long, race_raw,
"Participants by race (individual count)", "Race"),
bar_plot(survey, q_demos_education,
"Education level", "Education", text_size = 2.8),
bar_plot(survey, q_demos_gender,
"Declared gender identity", "Gender"),
bar_plot(survey, q_sexual_orientation,
"Declared sexual orientation", "Orientation"),
bar_plot(survey, q_demos_state,
"State distribution", "State", text_size = 2.4),
bar_plot(survey, q_amazon_use_howmany,
"People sharing Amazon account", "Number of people"),
bar_plot(survey, q_amazon_use_hh_size,
"Household size", "People in household"),
bar_plot(survey, q_amazon_use_how_oft,
"Amazon order frequency", "Frequency"),
bar_plot(survey, q_substance_use_1,
"Household cigarette use", "Response"),
bar_plot(survey, q_substance_use_2,
"Household marijuana use", "Response"),
bar_plot(survey, q_substance_use_3,
"Household alcohol use", "Response"),
bar_plot(survey, q_personal_1,
"Diabetes in household", "Response"),
bar_plot(survey, q_personal_2,
"Wheelchair use in household", "Response"),
bar_plot(survey, q_life_changes,
"Life changes in 2021 (combinations)", "Combination",
text_size = 2.8),
bar_plot(life_long, life_raw,
"Life changes in 2021 (individual)", "Life change"),
bar_plot(survey, q_demos_income,
"Income range", "Response")
)
# [MOD-01] Nombre del PDF cambiado para Adidas
out_pdf <- "survey_barplots_adidas.pdf"
grDevices::pdf(out_pdf, width = 10, height = 7)
for (p in plots_survey) print(p)
grDevices::dev.off()## png
## 2
## Saved: survey_barplots_adidas.pdf
Output esperado: El mensaje
Saved: survey_barplots_adidas.pdfconfirmando que el archivo fue escrito en el directorio de trabajo. El PDF tendrá 20 páginas, una por gráfico.
code1.R (caso Apple)| Bloque | Estado | Detalle |
|---|---|---|
| 1 — Paquetes | Sin cambios | Mismos paquetes |
| 2 — Config visual | Sin cambios | Misma paleta y locale |
3 — Funciones (bar_plot, mode_safe,
reorder_drop_id) |
Sin cambios | Funciones idénticas al original |
4 — Carga survey (survey.csv) |
Sin cambios | Mismo archivo |
| 5 — Race dummies | Sin cambios | Mismos 6 niveles, mismo pipeline |
| 6 — Life dummies | Sin cambios | Mismos 5 niveles, mismo pipeline |
7 — survey_enriched |
Sin cambios | Mismo merge con left_join |
| 8 — Gráficos individuales | Sin cambios | Mismas 20 variables |
| 9 — Export PDF | MOD-01 | PDF renombrado a survey_barplots_adidas.pdf |