1 1. Importación, limpieza y construcción de puntajes

library(tidyverse)   # dplyr, tidyr, ggplot2, stringr
library(readxl)
library(janitor)
library(stringi)
library(psych)

# --- Funciones auxiliares (sin backslashes problemáticos) ---
norm_name <- function(x){
  x %>% stringi::stri_trans_general("Latin-ASCII") %>% tolower() %>% gsub("[[:space:]]+"," ",.) %>% trimws()
}
pick_sheet <- function(all_sheets, target){
  s_norm <- norm_name(all_sheets); t_norm <- norm_name(target)
  idx <- which(s_norm == t_norm); if(length(idx)==1) return(all_sheets[idx])
  idx2 <- which(grepl(t_norm, s_norm, fixed=TRUE)); if(length(idx2)>=1) return(all_sheets[idx2[1]])
  NA_character_
}

# Detectar hojas de forma robusta
sheets <- readxl::excel_sheets(path = params$archivo_excel)
sheet_datos    <- pick_sheet(sheets, params$hoja_datos)
sheet_factores <- pick_sheet(sheets, params$hoja_factores)
sheet_diccionario <- pick_sheet(sheets, params$hoja_diccionario)
if(is.na(sheet_datos)) stop("No se encontró la hoja 'datos'.")
if(is.na(sheet_factores)) stop("No se encontró la hoja 'factores'.")

# Leer 'datos' y limpiar
raw <- readxl::read_excel(params$archivo_excel, sheet = sheet_datos) %>% janitor::clean_names()
# Si existe 'licenciatura', renombrar a 'ingenieria'
if("licenciatura" %in% names(raw)) raw <- dplyr::rename(raw, ingenieria = licenciatura)

# Homologar
raw <- raw %>% dplyr::mutate(
  sexo = stringr::str_to_title(sexo),
  ingenieria = stringr::str_trim(ingenieria),
  semestre = as.factor(semestre)
)

# Ítems p1..p34
item_cols <- names(raw)[grepl("^p[0-9]+$", names(raw))]
raw <- raw %>% dplyr::mutate(dplyr::across(dplyr::all_of(item_cols), as.numeric))

# Leer 'factores'
factores_tbl <- readxl::read_excel(params$archivo_excel, sheet = sheet_factores) %>% janitor::clean_names()
names(factores_tbl) <- norm_name(names(factores_tbl))
col_factor <- if("factores" %in% names(factores_tbl)) "factores" else names(factores_tbl)[1]
col_items  <- if("items" %in% names(factores_tbl)) "items" else names(factores_tbl)[2]
factores_tbl <- factores_tbl %>% dplyr::select(dplyr::all_of(c(col_factor, col_items))) %>% dplyr::rename(nombre_factor = !!col_factor, items_txt = !!col_items)

# Separar lista de ítems con coma + espacios normales
factores_tbl$items <- strsplit(factores_tbl$items_txt, ", *")

# Lista nombrada y estandarizada
factores <- setNames(factores_tbl$items, factores_tbl$nombre_factor)
factores <- lapply(factores, function(v) gsub(" +","", tolower(v)))

# Puntajes por escala
for(fname in names(factores)){
  its <- intersect(factores[[fname]], names(raw))
  if(length(its) > 0){ raw[[paste0("score_", fname)]] <- rowMeans(raw[, its], na.rm = TRUE) }
}

# Puntaje global
items_1_34 <- paste0("p", 1:34)
presentes  <- intersect(items_1_34, names(raw))
raw$score_global <- rowMeans(raw[, presentes], na.rm = TRUE)

cat(sprintf("Filas: %d\nColumnas: %d\n", nrow(raw), ncol(raw)))
## Filas: 95
## Columnas: 46

1.1 1.1 Resumen de la muestra

tabla_sexo <- raw %>% dplyr::count(sexo)
tabla_ing  <- raw %>% dplyr::count(ingenieria)
tabla_sem  <- raw %>% dplyr::count(semestre)
knitr::kable(tabla_sexo, caption = "Distribución por sexo")
Distribución por sexo
sexo n
Hombre 65
Mujer 30
knitr::kable(tabla_ing,  caption = "Distribución por ingeniería")
Distribución por ingeniería
ingenieria n
Ambiental 12
Civil 21
Industrial 11
Mecatronica 17
Software y Sistemas Computacionales 34
knitr::kable(tabla_sem,  caption = "Distribución por semestre")
Distribución por semestre
semestre n
54
8 41

2 2. Descriptivos y frecuencias Likert

items_presentes <- presentes
# Descriptivos por ítem
desc_items <- raw %>% dplyr::summarise(dplyr::across(dplyr::all_of(items_presentes), list(Media = ~mean(.x, na.rm=TRUE), SD = ~sd(.x, na.rm=TRUE)), .names="{.col}_{.fn}")) %>%
  tidyr::pivot_longer(dplyr::everything(), names_to = c("item", ".value"), names_sep = "_")
knitr::kable(desc_items, digits = 2, caption = "Descriptivos por ítem (Media y Desviación estándar)")
Descriptivos por ítem (Media y Desviación estándar)
item Media SD
p1 3.76 0.78
p2 3.35 0.77
p3 3.23 0.82
p4 3.49 0.84
p5 3.58 0.86
p6 3.77 0.82
p7 3.67 0.87
p8 3.57 0.91
p9 3.71 0.85
p10 3.83 0.75
p11 3.81 0.85
p12 3.61 0.91
p13 3.44 0.99
p14 3.41 0.79
p15 3.45 0.83
p16 3.71 0.84
p17 3.41 0.81
p18 3.95 0.79
p19 3.62 0.84
p20 3.45 0.91
p21 3.12 0.84
p22 3.25 0.85
p23 3.12 0.94
p24 3.44 0.81
p25 3.69 0.83
p26 3.62 0.75
p27 3.93 0.84
p28 3.84 0.75
p29 4.03 0.82
p30 3.85 0.81
p31 3.86 0.79
p32 3.58 0.89
p33 3.87 0.79
p34 3.69 0.93
likert_long <- raw %>% dplyr::select(dplyr::all_of(items_presentes)) %>% tidyr::pivot_longer(dplyr::everything(), names_to = "item", values_to = "respuesta")
freq_likert <- likert_long %>% dplyr::count(item, respuesta) %>% dplyr::group_by(item) %>% dplyr::mutate(prop = n/sum(n)) %>% dplyr::ungroup()
readr::write_csv(freq_likert, "salidas/tablas/frecuencias_likert.csv")

library(ggplot2)
g1 <- ggplot(freq_likert, aes(x = item, y = prop, fill = factor(respuesta, levels = 1:5, labels = c("Nunca","Rara vez","A veces","Frecuentemente","Siempre")))) +
  geom_col(width = 0.9) + scale_y_continuous(labels = scales::percent_format()) + scale_fill_brewer(palette = "RdYlGn", direction = 1, name = "Respuesta") +
  labs(title = "Distribución de respuestas Likert por ítem", x = "Ítem", y = "%") + theme_minimal() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5))

ggsave(filename = "salidas/figuras/likert_items.png", plot = g1, width = params$ancho_png, height = params$alto_png, dpi = params$dpi_png)

3 3. Modelo global (sexo × ingeniería × semestre) y funciones auxiliares

library(car)
library(emmeans)
library(effectsize)
library(ARTool)
library(tidyr)
library(ggplot2)

# Gráfico emmeans
plot_emmeans <- function(emm_obj, y, nombre){
  plt <- plot(emm_obj, comparisons = TRUE) +
    ggplot2::labs(title = paste0("Medias marginales (IC95): ", y), x = "Grupo", y = "Puntaje (1–5)") +
    ggplot2::theme_minimal()
  ggplot2::ggsave(file.path("salidas/figuras", paste0(nombre, ".png")), plot = plt, width = params$ancho_png, height = params$alto_png, dpi = params$dpi_png)
}

# Wrapper seguro para ANOVA
safe_Anova <- function(fit){
  res <- try(car::Anova(fit, type = "III", singular.ok = TRUE), silent = TRUE)
  if (inherits(res, "try-error")){
    res <- car::Anova(fit, type = "II")
  }
  res
}

# Chequeo de supuestos
checar_supuestos <- function(df, y){
  df <- df %>% tidyr::drop_na(sexo, ingenieria, semestre, !!rlang::sym(y)) %>%
    dplyr::mutate(sexo = as.factor(sexo), ingenieria = as.factor(ingenieria), semestre = as.factor(semestre)) %>%
    droplevels()
  fit <- stats::lm(stats::as.formula(paste(y, "~ sexo * ingenieria * semestre")), data = df)
  shapiro_p <- stats::shapiro.test(stats::residuals(fit))$p.value
  lev_p <- car::leveneTest(stats::as.formula(paste(y, "~ interaction(sexo, ingenieria, semestre)")), data = df)$`Pr(>F)`[1]
  list(fit=fit, shapiro_p=shapiro_p, lev_p=lev_p)
}

# Analiza escala con LM o ART (ART requiere efectos completamente cruzados)
analiza_escala <- function(df, y, usar_art = FALSE){
  df <- df %>% tidyr::drop_na(sexo, ingenieria, semestre, !!rlang::sym(y)) %>%
    dplyr::mutate(sexo = as.factor(sexo), ingenieria = as.factor(ingenieria), semestre = as.factor(semestre)) %>%
    droplevels()
  if(!usar_art){
    fit <- stats::lm(stats::as.formula(paste(y, "~ sexo * ingenieria * semestre")), data = df)
    aov_tab <- safe_Anova(fit)
    eff <- effectsize::eta_squared(fit, partial = TRUE)
    emm <- emmeans::emmeans(fit, ~ sexo * ingenieria | semestre)
    posthoc <- emmeans::contrast(emm, method = "pairwise", adjust = "holm")
    list(model="LM", aov=aov_tab, efectos=eff, emm=emm, posthoc=posthoc)
  } else {
    fit <- ARTool::art(stats::as.formula(paste(y, "~ sexo * ingenieria * semestre")), data = df)
    aov_tab <- stats::anova(fit)
    emm <- emmeans::emmeans(fit, ~ sexo * ingenieria | semestre)
    posthoc <- emmeans::contrast(emm, method = "pairwise", adjust = "holm")
    list(model="ART", aov=aov_tab, efectos=NULL, emm=emm, posthoc=posthoc)
  }
}

sup_global <- checar_supuestos(raw, "score_global")
usar_art_global <- !(sup_global$shapiro_p > 0.05 && sup_global$lev_p > 0.05)
res_global <- analiza_escala(raw, "score_global", usar_art = usar_art_global)

# Exportar resultados (independiente del tipo)
aov_global <- res_global$aov
write.csv(as.data.frame(aov_global), "salidas/tablas/anova_global.csv", row.names = TRUE)
if(!is.null(res_global$efectos)) write.csv(as.data.frame(res_global$efectos), "salidas/tablas/eta2parcial_global.csv", row.names = FALSE)

posthoc_global <- summary(res_global$posthoc, infer = TRUE)
write.csv(as.data.frame(posthoc_global), "salidas/tablas/posthoc_global.csv", row.names = FALSE)
plot_emmeans(res_global$emm, "score_global", "emmeans_global")

# Raincloud global
draw_raincloud <- function(df, y, nombre){
  p <- df %>% ggplot2::ggplot(ggplot2::aes(x = interaction(sexo, ingenieria, drop = TRUE), y = .data[[y]], fill = sexo)) +
    ggplot2::geom_violin(alpha = 0.5, trim = FALSE) + ggplot2::geom_boxplot(width = 0.15, outlier.alpha = 0.2) +
    ggplot2::geom_jitter(width = 0.1, alpha = 0.25) + ggplot2::facet_wrap(~ semestre) +
    ggplot2::labs(title = paste0("Distribución por sexo × ingeniería (facet semestre): ", y), x = "Sexo × Ingeniería", y = "Puntaje (1–5)") +
    ggplot2::theme_minimal() + ggplot2::guides(fill = "none")
  ggplot2::ggsave(file.path("salidas/figuras", paste0(nombre, "_raincloud.png")), plot = p, width = 12, height = 6.5, dpi = params$dpi_png)
}
draw_raincloud(raw, "score_global", "global")

4 4. Secundarios (escalas) y FDR

library(rstatix)

escalas <- c("score_generar_motivacion","score_comunicacion_no_verbal","score_empatia",
             "score_expresion_emocional","score_expresion_oral",
             "score_transmision_informativa","score_abierta_autentica","score_escucha")

resultados_escalas <- list(); pv_escalas <- c(); labels <- c(); escala_vec <- c()
for(y in escalas){
  sup <- checar_supuestos(raw, y)
  usar_art <- !(sup$shapiro_p > 0.05 && sup$lev_p > 0.05)
  res <- analiza_escala(raw, y, usar_art = usar_art)
  resultados_escalas[[y]] <- res

  aov_tab <- res$aov
  write.csv(as.data.frame(aov_tab), file.path("salidas/tablas", paste0("anova_", y, ".csv")))
  if(!is.null(res$efectos)) write.csv(as.data.frame(res$efectos), file.path("salidas/tablas", paste0("eta2parcial_", y, ".csv")), row.names = FALSE)

  pv <- aov_tab$`Pr(>F)`; rn <- rownames(aov_tab)
  idx <- which(rn %in% c("sexo","ingenieria","semestre","sexo:ingenieria","sexo:semestre","ingenieria:semestre","sexo:ingenieria:semestre"))
  pv_escalas <- c(pv_escalas, pv[idx]); labels <- c(labels, rn[idx]); escala_vec <- c(escala_vec, rep(y, length(idx)))

  posthoc <- summary(res$posthoc, infer = TRUE)
  write.csv(as.data.frame(posthoc), file.path("salidas/tablas", paste0("posthoc_", y, ".csv")), row.names = FALSE)
  plot_emmeans(res$emm, y, paste0("emmeans_", y))
  draw_raincloud(raw, y, y)
}

# FDR por escala x efecto
fdr_tab <- tibble::tibble(
  escala = escala_vec,
  efecto = labels,
  p_raw  = pv_escalas,
  p_fdr  = p.adjust(pv_escalas, method = "BH")
)
knitr::kable(fdr_tab, digits = 4, caption = "FDR (Benjamini–Hochberg) en efectos por escala")
FDR (Benjamini–Hochberg) en efectos por escala
escala efecto p_raw p_fdr
score_generar_motivacion sexo NA NA
score_generar_motivacion ingenieria NA NA
score_generar_motivacion semestre NA NA
score_generar_motivacion sexo:ingenieria NA NA
score_generar_motivacion sexo:semestre NA NA
score_generar_motivacion ingenieria:semestre NA NA
score_generar_motivacion sexo:ingenieria:semestre NA NA
score_comunicacion_no_verbal sexo NA NA
score_comunicacion_no_verbal ingenieria NA NA
score_comunicacion_no_verbal semestre NA NA
score_comunicacion_no_verbal sexo:ingenieria NA NA
score_comunicacion_no_verbal sexo:semestre NA NA
score_comunicacion_no_verbal ingenieria:semestre NA NA
score_comunicacion_no_verbal sexo:ingenieria:semestre NA NA
score_empatia sexo NA NA
score_empatia ingenieria NA NA
score_empatia semestre NA NA
score_empatia sexo:ingenieria NA NA
score_empatia sexo:semestre NA NA
score_empatia ingenieria:semestre NA NA
score_empatia sexo:ingenieria:semestre NA NA
score_expresion_emocional sexo NA NA
score_expresion_emocional ingenieria NA NA
score_expresion_emocional semestre NA NA
score_expresion_emocional sexo:ingenieria NA NA
score_expresion_emocional sexo:semestre NA NA
score_expresion_emocional ingenieria:semestre NA NA
score_expresion_emocional sexo:ingenieria:semestre NA NA
score_expresion_oral sexo NA NA
score_expresion_oral ingenieria NA NA
score_expresion_oral semestre NA NA
score_expresion_oral sexo:ingenieria NA NA
score_expresion_oral sexo:semestre NA NA
score_expresion_oral ingenieria:semestre NA NA
score_expresion_oral sexo:ingenieria:semestre NA NA
score_transmision_informativa sexo NA NA
score_transmision_informativa ingenieria NA NA
score_transmision_informativa semestre NA NA
score_transmision_informativa sexo:ingenieria NA NA
score_transmision_informativa sexo:semestre NA NA
score_transmision_informativa ingenieria:semestre NA NA
score_transmision_informativa sexo:ingenieria:semestre NA NA
score_abierta_autentica sexo NA NA
score_abierta_autentica ingenieria NA NA
score_abierta_autentica semestre NA NA
score_abierta_autentica sexo:ingenieria NA NA
score_abierta_autentica sexo:semestre NA NA
score_abierta_autentica ingenieria:semestre NA NA
score_abierta_autentica sexo:ingenieria:semestre NA NA
score_escucha sexo NA NA
score_escucha ingenieria NA NA
score_escucha semestre NA NA
score_escucha sexo:ingenieria NA NA
score_escucha sexo:semestre NA NA
score_escucha ingenieria:semestre NA NA
score_escucha sexo:ingenieria:semestre NA NA
readr::write_csv(fdr_tab, "salidas/tablas/fdr_escalas.csv")

5 5. Descriptivos por sexo × ingeniería × semestre

desc_tab <- raw %>% dplyr::group_by(sexo, ingenieria, semestre) %>% dplyr::summarise(
  n = dplyr::n(),
  across(c(score_global, all_of(escalas)), list(Media = ~mean(.x, na.rm = TRUE), SD = ~sd(.x, na.rm = TRUE)), .names = "{.col}_{.fn}"),
  .groups = "drop"
)
knitr::kable(desc_tab, digits = 2, caption = "Descriptivos por sexo × ingeniería × semestre (global y escalas)")
Descriptivos por sexo × ingeniería × semestre (global y escalas)
sexo ingenieria semestre n score_global_Media score_global_SD score_generar_motivacion_Media score_generar_motivacion_SD score_comunicacion_no_verbal_Media score_comunicacion_no_verbal_SD score_empatia_Media score_empatia_SD score_expresion_emocional_Media score_expresion_emocional_SD score_expresion_oral_Media score_expresion_oral_SD score_transmision_informativa_Media score_transmision_informativa_SD score_abierta_autentica_Media score_abierta_autentica_SD score_escucha_Media score_escucha_SD
Hombre Ambiental 8 2 4.07 0.48 4.00 0.47 4.20 0.57 4.50 0.71 3.67 0.47 4.12 0.18 3.88 0.53 4.40 0.57 3.50 0.24
Hombre Civil 8 3.30 0.34 3.17 0.48 3.50 0.68 3.66 0.68 3.04 0.70 3.28 0.47 3.19 0.73 3.18 0.73 3.38 0.52
Hombre Civil 8 9 3.46 0.42 3.37 0.54 3.67 0.53 3.61 0.53 3.15 0.47 3.56 0.72 3.25 0.71 3.60 0.39 3.37 0.54
Hombre Industrial 5 3.44 0.39 3.50 0.46 3.72 0.58 3.75 0.47 3.40 0.55 2.85 0.58 3.30 0.33 3.48 0.56 3.33 0.94
Hombre Mecatronica 9 3.53 0.55 3.39 0.70 3.42 0.52 3.89 0.64 3.41 0.76 3.50 0.48 3.50 0.50 3.47 0.70 3.85 0.69
Hombre Mecatronica 8 5 3.56 0.42 3.20 0.45 3.52 0.48 4.05 0.62 3.40 0.55 3.80 0.76 3.70 0.74 3.52 0.59 3.40 0.43
Hombre Software y Sistemas Computacionales 16 3.51 0.41 3.39 0.49 3.52 0.58 3.89 0.68 3.17 0.67 3.55 0.59 3.31 0.45 3.49 0.54 3.77 0.57
Hombre Software y Sistemas Computacionales 8 11 3.73 0.69 3.68 0.71 3.75 0.84 3.84 0.85 3.36 0.95 3.82 0.82 3.52 0.71 3.91 0.72 3.85 0.78
Mujer Ambiental 5 3.97 0.28 4.03 0.38 4.00 0.40 4.35 0.29 3.53 0.93 4.00 0.00 3.80 0.57 3.96 0.26 3.93 0.55
Mujer Ambiental 8 5 3.73 0.24 3.87 0.36 3.68 0.41 4.15 0.60 3.00 0.97 4.05 0.45 3.20 0.27 3.88 0.50 3.73 0.43
Mujer Civil 2 3.94 0.37 4.42 0.59 3.50 0.14 4.50 0.71 3.50 0.24 3.25 0.35 4.00 1.06 4.10 0.14 4.00 0.47
Mujer Civil 8 2 3.71 0.17 3.25 0.12 4.20 0.85 4.12 0.18 3.00 0.00 4.12 0.53 3.25 0.00 3.90 0.14 3.67 0.00
Mujer Industrial 6 3.91 0.43 3.92 0.39 4.13 0.55 4.17 0.65 3.44 0.69 3.96 0.83 3.75 0.47 3.83 0.53 3.94 0.44
Mujer Mecatronica 3 3.49 0.62 3.33 0.60 3.87 0.95 3.25 0.43 3.56 0.96 3.67 0.72 3.58 0.80 3.13 0.42 3.67 0.88
Mujer Software y Sistemas Computacionales 8 7 3.66 0.46 3.79 0.46 3.63 0.79 4.07 0.40 3.05 0.99 3.82 0.89 3.57 0.66 3.54 0.40 3.62 0.71
readr::write_csv(desc_tab, "salidas/tablas/descriptivos_por_grupo.csv")

6 6. (Opcional) Validación del instrumento — deshabilitada para evitar interrupciones

library(lavaan)
# EFA
png("salidas/figuras/fa_parallel.png", width = params$ancho_png*96, height = params$alto_png*96)
psych::fa.parallel(raw[, presentes], fa = "fa", fm = "ml")
dev.off()
fa_ml <- psych::fa(raw[, presentes], nfactors = 8, fm = "ml", rotate = "oblimin")
loadings_df <- as.data.frame(unclass(fa_ml$loadings))
readr::write_csv(loadings_df, "salidas/tablas/efa_cargas.csv")

# CFA desde 'factores'
model_lines <- c()
for(fname in names(factores)){
  its <- intersect(factores[[fname]], presentes)
  if(length(its)>0) model_lines <- c(model_lines, paste0(gsub("[^A-Za-z0-9]", "_", fname), " =~ ", paste(its, collapse = " + ")))
}
model_cfa <- paste(model_lines, collapse = "\n")
fit_cfa <- lavaan::cfa(model_cfa, data = raw, estimator = "MLR")
summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)
fit_measures <- data.frame(t(lavaan::fitMeasures(fit_cfa, c("cfi","tli","rmsea","srmr","chisq","df","pvalue"))))
readr::write_csv(fit_measures, "salidas/tablas/cfa_indices_ajuste.csv")

# Invariancia por sexo
fit_config <- lavaan::cfa(model_cfa, data = raw, group = "sexo", estimator = "MLR")
fit_metric <- lavaan::cfa(model_cfa, data = raw, group = "sexo", group.equal = c("loadings"), estimator = "MLR")
fit_scalar <- lavaan::cfa(model_cfa, data = raw, group = "sexo", group.equal = c("loadings","intercepts"), estimator = "MLR")
comp_invar <- lavaan::anova(fit_config, fit_metric, fit_scalar)
readr::write_csv(as.data.frame(comp_invar), "salidas/tablas/invariancia_sexo_comp.csv")

7 7. Margen de error (95%) con corrección por población finita

N <- params$N_poblacion
n <- nrow(raw)
conf <- 0.95
z <- qnorm(1 - (1-conf)/2)
p <- 0.5
moe_prop <- z * sqrt(p*(1-p)/n) * sqrt((N-n)/(N-1))

factor_scores <- raw %>% dplyr::select(dplyr::starts_with("score_"), score_global)
moe_medias <- factor_scores %>% dplyr::summarise(dplyr::across(dplyr::everything(), ~ z * sd(.x, na.rm=TRUE)/sqrt(n) * sqrt((N-n)/(N-1)))) %>% tidyr::pivot_longer(dplyr::everything(), names_to = "escala", values_to = "MOE")

knitr::kable(tibble::tibble(
  `Tamaño de muestra (n)` = n,
  `Población (N)`        = N,
  `Nivel de confianza`   = paste0(conf*100, "%"),
  `Margen de error (proporción, p=0.5)` = scales::percent(moe_prop, accuracy = 0.1)
), caption = "Parámetros de estimación con corrección por población finita")
Parámetros de estimación con corrección por población finita
Tamaño de muestra (n) Población (N) Nivel de confianza Margen de error (proporción, p=0.5)
95 122 95% 4.7%
knitr::kable(moe_medias, digits = 3, caption = "Margen de error de la media por escala (95% CI, FPC)")
Margen de error de la media por escala (95% CI, FPC)
escala MOE
score_generar_motivacion 0.054
score_comunicacion_no_verbal 0.059
score_empatia 0.060
score_expresion_emocional 0.068
score_expresion_oral 0.064
score_transmision_informativa 0.056
score_abierta_autentica 0.056
score_escucha 0.058
score_global 0.045
readr::write_csv(moe_medias, "salidas/tablas/margen_error_medias.csv")

8 8. Decisiones editoriales

cat("Se utiliza α = ", params$alpha, " para pruebas principales.\n")
## Se utiliza α =  0.05  para pruebas principales.
cat("Secundarios (escalas): FDR (Benjamini–Hochberg) en efectos principales e interacción.\n")
## Secundarios (escalas): FDR (Benjamini–Hochberg) en efectos principales e interacción.
cat("Post hoc: emmeans::contrast(method = 'pairwise', ajuste Holm) con IC95.\n")
## Post hoc: emmeans::contrast(method = 'pairwise', ajuste Holm) con IC95.

9 9. Información de sesión

sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Mexico.utf8  LC_CTYPE=Spanish_Mexico.utf8   
## [3] LC_MONETARY=Spanish_Mexico.utf8 LC_NUMERIC=C                   
## [5] LC_TIME=Spanish_Mexico.utf8    
## 
## time zone: America/Mexico_City
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] rstatix_0.7.3    ARTool_0.11.2    effectsize_1.0.1 emmeans_1.11.2-8
##  [5] car_3.1-3        carData_3.0-5    psych_2.5.6      stringi_1.8.7   
##  [9] janitor_2.2.1    readxl_1.4.5     lubridate_1.9.4  forcats_1.0.1   
## [13] stringr_1.5.2    dplyr_1.1.4      purrr_1.1.0      readr_2.1.5     
## [17] tidyr_1.3.1      tibble_3.3.0     ggplot2_4.0.1    tidyverse_2.0.0 
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.1   farver_2.1.2       S7_0.2.0           fastmap_1.2.0     
##  [5] bayestestR_0.17.0  digest_0.6.37      estimability_1.5.1 timechange_0.3.0  
##  [9] lifecycle_1.0.4    magrittr_2.0.4     compiler_4.5.1     rlang_1.1.6       
## [13] sass_0.4.10        tools_4.5.1        yaml_2.3.10        knitr_1.50        
## [17] labeling_0.4.3     bit_4.6.0          mnormt_2.1.1       plyr_1.8.9        
## [21] RColorBrewer_1.1-3 abind_1.4-8        withr_3.0.2        grid_4.5.1        
## [25] datawizard_1.3.0   xtable_1.8-4       scales_1.4.0       MASS_7.3-65       
## [29] insight_1.4.4      cli_3.6.5          mvtnorm_1.3-3      rmarkdown_2.30    
## [33] crayon_1.5.3       ragg_1.5.0         reformulas_0.4.1   generics_0.1.4    
## [37] rstudioapi_0.17.1  tzdb_0.5.0         parameters_0.28.3  minqa_1.2.8       
## [41] cachem_1.1.0       splines_4.5.1      parallel_4.5.1     cellranger_1.1.0  
## [45] vctrs_0.6.5        boot_1.3-32        Matrix_1.7-4       jsonlite_2.0.0    
## [49] hms_1.1.4          bit64_4.6.0-1      Formula_1.2-5      systemfonts_1.3.1 
## [53] jquerylib_0.1.4    glue_1.8.0         nloptr_2.2.1       gtable_0.3.6      
## [57] lme4_1.1-37        pillar_1.11.1      htmltools_0.5.8.1  R6_2.6.1          
## [61] textshaping_1.0.4  Rdpack_2.6.4       vroom_1.6.6        evaluate_1.0.5    
## [65] lattice_0.22-7     backports_1.5.0    rbibutils_2.3      broom_1.0.10      
## [69] snakecase_0.11.1   bslib_0.9.0        Rcpp_1.1.0         nlme_3.1-168      
## [73] xfun_0.53          pkgconfig_2.0.3