Este documento presenta el análisis estadístico completo de la encuesta aplicada a estudiantes de la Facultad de Ciencias Exactas y Naturales de la Universidad Surcolombiana, sede Neiva. El objetivo es analizar las tendencias de pensamiento sobre el potencial científico y la aplicabilidad de la energía nuclear, y correlacionarlas con variables socioculturales y formativas.
Pregunta de investigación: ¿En qué medida las variables socioculturales y formativas predicen las tendencias de pensamiento sobre la energía nuclear y su potencial científico en los estudiantes de la Facultad de Ciencias Exactas y Naturales de la Universidad Surcolombiana, sede Neiva?
# Instalar paquetes si no están disponibles
paquetes <- c("readxl", "dplyr", "ggplot2", "psych", "car", "knitr",
"kableExtra", "tidyr", "scales", "ggpubr", "rstatix",
"corrplot", "likert", "nnet", "lm.beta", "moments")
instalar <- paquetes[!paquetes %in% installed.packages()[,"Package"]]
if (length(instalar) > 0) install.packages(instalar, repos = "https://cran.r-project.org")
suppressPackageStartupMessages({
library(readxl)
library(dplyr)
library(ggplot2)
library(psych)
library(car)
library(knitr)
library(kableExtra)
library(tidyr)
library(scales)
library(ggpubr)
library(rstatix)
library(corrplot)
library(moments)
})# ── Carga del archivo ──────────────────────────────────────────────────────────
# INSTRUCCIÓN RÁPIDA:
# 1. Pon el .Rmd y el .xlsx en la misma carpeta.
# 2. En RStudio: Session > Set Working Directory > To Source File Location
# 3. Haz clic en Knit.
#
# Si prefieres indicar la ruta manualmente, edita la siguiente línea:
ruta_manual <- ""
# Ejemplo Windows : ruta_manual <- "C:/Users/Ana/Escritorio/Cuestionario_final__respuestas.xlsx"
# Ejemplo Mac/Linux: ruta_manual <- "/Users/ana/Escritorio/Cuestionario_final__respuestas.xlsx"
nombre_xlsx <- "Cuestionario_final__respuestas.xlsx"
ruta_excel <- if (nchar(trimws(ruta_manual)) > 0) ruta_manual else nombre_xlsx
if (!file.exists(ruta_excel)) {
# Intento extra: buscar en carpetas comunes de Windows/Mac
posibles <- c(
file.path(Sys.getenv("USERPROFILE"), "Desktop", nombre_xlsx),
file.path(Sys.getenv("HOME"), "Desktop", nombre_xlsx),
file.path(Sys.getenv("USERPROFILE"), "Escritorio", nombre_xlsx),
file.path(Sys.getenv("HOME"), "Escritorio", nombre_xlsx),
file.path(Sys.getenv("USERPROFILE"), "Downloads", nombre_xlsx),
file.path(Sys.getenv("HOME"), "Downloads", nombre_xlsx)
)
encontrado <- posibles[file.exists(posibles)]
if (length(encontrado) > 0) {
ruta_excel <- encontrado[1]
cat("Archivo encontrado automáticamente en:", ruta_excel, "\n")
} else {
stop(paste0(
"\n\nNo se encontró '", nombre_xlsx, "'.\n",
"SOLUCIÓN DIRECTA: edita la línea ruta_manual en este chunk.\n",
"Ejemplo: ruta_manual <- \"C:/Users/User/Desktop/proyecto/",
nombre_xlsx, "\"\n",
"Directorio actual: ", normalizePath(getwd()), "\n"
))
}
}
cat("Archivo cargado desde:", normalizePath(ruta_excel), "\n")## Archivo cargado desde: C:\Users\User\Desktop\Cuestionario_final__respuestas.xlsx
datos_raw <- read_excel(ruta_excel, sheet = 1)
# ── Nombres cortos de columnas ─────────────────────────────────────────────────
nombres_nuevos <- c(
"timestamp", "edad", "semestre", "programa", "sexo",
paste0("P", 1:20),
"texto_conocimiento", "texto_beneficios_riesgos",
"texto_fuentes", "texto_eleccion", "texto_formacion"
)
colnames(datos_raw) <- nombres_nuevos
# ── Conversión Likert: extraer número inicial ──────────────────────────────────
convertir_likert <- function(x) {
as.integer(sub("^(\\d+).*", "\\1", trimws(as.character(x))))
}
datos <- datos_raw %>%
mutate(across(P1:P20, convertir_likert)) %>%
filter(rowSums(is.na(select(., P1:P20))) < 10) # elimina filas casi vacías
# ── Variables categóricas limpias ─────────────────────────────────────────────
datos <- datos %>%
mutate(
programa = factor(trimws(programa),
levels = c("Biología", "Física", "Matemática Aplicada")),
sexo = factor(trimws(sexo),
levels = c("Femenino", "Masculino")),
edad = factor(trimws(edad),
levels = c("Menos de 18", "18 – 22", "23 – 27",
"28 – 32", "Más de 32"))
)
# ── Dimensiones teóricas ──────────────────────────────────────────────────────
# D1 Conocimiento/conciencia (P1-P4)
# D2 Percepción de riesgos (P5, P7, P9)
# D3 Actitud favorable (P6, P10, P11, P12, P13, P14)
# D4 Influencia mediática/formativa (P15, P16, P17)
# D5 Comparación de riesgos (P18, P19, P20)
# P8 puede ir en D2 o D5 (es inversa en D2)
datos <- datos %>%
rowwise() %>%
mutate(
D1_conocimiento = mean(c(P1, P2, P3, P4), na.rm = TRUE),
D2_riesgo = mean(c(P5, P7, P9), na.rm = TRUE),
D3_actitud = mean(c(P6, P10, P11, P12, P13, P14), na.rm = TRUE),
D4_influencia = mean(c(P15, P16, P17), na.rm = TRUE),
D5_comparacion = mean(c(P18, P19, P20), na.rm = TRUE),
puntaje_total = mean(c_across(P1:P20), na.rm = TRUE)
) %>%
ungroup()
cat("Dimensiones del dataset final:", nrow(datos), "observaciones,",
ncol(datos), "variables.\n")## Dimensiones del dataset final: 234 observaciones, 36 variables.
# ── Parámetros de diseño ───────────────────────────────────────────────────────
poblacion_total <- 596
n_total <- 234
n_biologia <- 136
n_fisica <- 46
n_matematica <- 52
tabla_muestra <- data.frame(
Programa = c("Biología", "Física", "Matemática Aplicada", "TOTAL"),
Población_N = c(round(poblacion_total * 136/234),
round(poblacion_total * 46/234),
round(poblacion_total * 52/234),
poblacion_total),
Muestra_n = c(n_biologia, n_fisica, n_matematica, n_total),
Fracción_muestreo = c(
round(n_biologia / round(poblacion_total*136/234), 3),
round(n_fisica / round(poblacion_total*46/234), 3),
round(n_matematica / round(poblacion_total*52/234), 3),
round(n_total / poblacion_total, 3)
)
)
kable(tabla_muestra,
caption = "Tabla 1. Diseño muestral estratificado proporcional",
align = "lrrr") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
row_spec(4, bold = TRUE, background = "#d4e6f1")| Programa | Población_N | Muestra_n | Fracción_muestreo |
|---|---|---|---|
| Biología | 346 | 136 | 0.393 |
| Física | 117 | 46 | 0.393 |
| Matemática Aplicada | 132 | 52 | 0.394 |
| TOTAL | 596 | 234 | 0.393 |
Método: Muestreo aleatorio simple por estratos proporcionales (programa académico). Nivel de confianza: 95 %, margen de error estimado: ±5 %.
# Distribución por programa
tab_prog <- datos %>% count(programa) %>%
mutate(Porcentaje = round(n/sum(n)*100, 1))
kable(tab_prog, col.names = c("Programa", "n", "%"),
caption = "Tabla 2. Distribución por programa académico") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Programa | n | % |
|---|---|---|
| Biología | 136 | 58.1 |
| Física | 46 | 19.7 |
| Matemática Aplicada | 52 | 22.2 |
# Distribución por sexo
tab_sexo <- datos %>% count(sexo) %>%
mutate(Porcentaje = round(n/sum(n)*100, 1))
kable(tab_sexo, col.names = c("Sexo", "n", "%"),
caption = "Tabla 3. Distribución por sexo") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Sexo | n | % |
|---|---|---|
| Femenino | 114 | 48.7 |
| Masculino | 120 | 51.3 |
# Distribución por edad
tab_edad <- datos %>% count(edad) %>%
mutate(Porcentaje = round(n/sum(n)*100, 1))
kable(tab_edad, col.names = c("Rango de edad", "n", "%"),
caption = "Tabla 4. Distribución por rango de edad") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Rango de edad | n | % |
|---|---|---|
| Menos de 18 | 28 | 12.0 |
| 18 – 22 | 140 | 59.8 |
| 23 – 27 | 47 | 20.1 |
| 28 – 32 | 14 | 6.0 |
| Más de 32 | 5 | 2.1 |
📊 Interpretación del perfil sociodemográfico: La distribución por programa replica el diseño estratificado; Biología concentra la mayor proporción de estudiantes. Por sexo, la muestra está casi equilibrada (masculino ≈ 51 %, femenino ≈ 49 %), lo que permite comparaciones sin sesgo de género. Por edad, el grupo predominante es el de 18–22 años (≈ 60 %), coherente con la población universitaria de pregrado; la presencia minoritaria de estudiantes mayores de 27 años puede reflejar trayectorias académicas no lineales y podría introducir mayor madurez reflexiva sobre temas científicos.
g1 <- ggplot(datos, aes(x = programa, fill = programa)) +
geom_bar(color = "white") +
geom_text(stat = "count", aes(label = ..count..), vjust = -0.4, size = 3.5) +
scale_fill_manual(values = c("#2196F3", "#FF5722", "#4CAF50")) +
labs(title = "Distribución por programa", x = NULL, y = "Frecuencia") +
theme_minimal(base_size = 11) + theme(legend.position = "none")
g2 <- ggplot(datos, aes(x = sexo, fill = sexo)) +
geom_bar(color = "white") +
geom_text(stat = "count", aes(label = ..count..), vjust = -0.4, size = 3.5) +
scale_fill_manual(values = c("#E91E63", "#3F51B5")) +
labs(title = "Distribución por sexo", x = NULL, y = "Frecuencia") +
theme_minimal(base_size = 11) + theme(legend.position = "none")
g3 <- ggplot(datos, aes(x = edad, fill = edad)) +
geom_bar(color = "white") +
geom_text(stat = "count", aes(label = ..count..), vjust = -0.4, size = 3.5) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Distribución por edad", x = NULL, y = "Frecuencia") +
theme_minimal(base_size = 11) + theme(legend.position = "none",
axis.text.x = element_text(angle = 20, hjust = 1))
ggpubr::ggarrange(g1, g2, g3, ncol = 3)items <- datos %>% select(P1:P20)
desc <- data.frame(
Ítem = paste0("P", 1:20),
n = colSums(!is.na(items)),
Media = round(colMeans(items, na.rm = TRUE), 2),
DE = round(apply(items, 2, sd, na.rm = TRUE), 2),
Mín = apply(items, 2, min, na.rm = TRUE),
Mediana = apply(items, 2, median, na.rm = TRUE),
Máx = apply(items, 2, max, na.rm = TRUE),
Asimetría = round(apply(items, 2, skewness, na.rm = TRUE), 2)
)
kable(desc, caption = "Tabla 5. Estadísticos descriptivos de los 20 ítems Likert (1–5)",
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, font_size = 11) %>%
column_spec(3, bold = TRUE)| Ítem | n | Media | DE | Mín | Mediana | Máx | Asimetría |
|---|---|---|---|---|---|---|---|
| P1 | 234 | 3.36 | 1.15 | 1 | 3.0 | 5 | -0.44 |
| P2 | 234 | 3.64 | 1.18 | 1 | 4.0 | 5 | -0.64 |
| P3 | 234 | 3.36 | 1.23 | 1 | 3.0 | 5 | -0.31 |
| P4 | 234 | 3.53 | 1.26 | 1 | 4.0 | 5 | -0.51 |
| P5 | 234 | 3.28 | 1.29 | 1 | 3.0 | 5 | -0.32 |
| P6 | 234 | 3.47 | 1.07 | 1 | 3.0 | 5 | -0.34 |
| P7 | 234 | 3.57 | 1.22 | 1 | 4.0 | 5 | -0.57 |
| P8 | 234 | 3.34 | 1.23 | 1 | 3.0 | 5 | -0.31 |
| P9 | 234 | 3.26 | 1.20 | 1 | 3.0 | 5 | -0.32 |
| P10 | 234 | 3.69 | 1.14 | 1 | 4.0 | 5 | -0.62 |
| P11 | 234 | 3.56 | 1.22 | 1 | 4.0 | 5 | -0.54 |
| P12 | 234 | 3.59 | 1.17 | 1 | 4.0 | 5 | -0.63 |
| P13 | 234 | 3.38 | 1.17 | 1 | 3.0 | 5 | -0.32 |
| P14 | 234 | 3.48 | 1.22 | 1 | 3.5 | 5 | -0.45 |
| P15 | 234 | 2.95 | 1.19 | 1 | 3.0 | 5 | 0.01 |
| P16 | 234 | 2.99 | 1.17 | 1 | 3.0 | 5 | -0.10 |
| P17 | 234 | 3.03 | 1.24 | 1 | 3.0 | 5 | -0.06 |
| P18 | 234 | 3.33 | 1.14 | 1 | 3.0 | 5 | -0.35 |
| P19 | 234 | 3.22 | 1.13 | 1 | 3.0 | 5 | -0.19 |
| P20 | 234 | 3.01 | 1.14 | 1 | 3.0 | 5 | -0.09 |
📊 Interpretación de la tabla descriptiva: Los ítems con media > 3.5 indican tendencia de acuerdo; los que tienen media < 2.5 indican desacuerdo predominante. Presta atención a la desviación estándar (DE): valores DE > 1.2 señalan alta dispersión, es decir, opiniones muy divididas dentro de la muestra — esto es relevante para el objetivo 1 (identificar tendencias). Los ítems con asimetría negativa fuerte (< −0.5) muestran que la mayoría se concentra en respuestas altas.
desc_long <- desc %>%
mutate(Etiqueta = c(
"P1: Conozco qué es la E.N.", "P2: Aplicaciones médicas",
"P3: Sin emisiones CO₂", "P4: Uranio como combustible",
"P5: Riesgo alto para salud/MA", "P6: Beneficiosa en salud",
"P7: Residuos mayor inconveniente", "P8: Contamina menos que conv.",
"P9: Riesgo de accidentes alto", "P10: Favorece desarrollo tecnológico",
"P11: Apoyaría su uso en Colombia", "P12: Alternativa al petróleo",
"P13: Sostenibilidad ambiental", "P14: Civil ≠ militar",
"P15: Medios influyen en mi opinión", "P16: Confío en regulación estatal",
"P17: Programa me informó objetivamente", "P18: Aire > riesgo que plantas",
"P19: Tráfico/calor > reactores", "P20: Residuos < pesticidas"
))
ggplot(desc_long, aes(x = reorder(Etiqueta, Media), y = Media, fill = Media)) +
geom_col(color = "white") +
geom_errorbar(aes(ymin = Media - DE, ymax = Media + DE), width = 0.3, alpha = 0.6) +
coord_flip() +
scale_fill_gradient2(low = "#f44336", mid = "#FFC107", high = "#4CAF50",
midpoint = 3, name = "Media") +
geom_hline(yintercept = 3, linetype = "dashed", color = "gray40") +
labs(title = "Media ± DE por ítem Likert",
subtitle = "Línea punteada = punto neutro (3)",
x = NULL, y = "Puntaje promedio (1–5)") +
scale_y_continuous(limits = c(0, 6)) +
theme_minimal(base_size = 10)📊 Interpretación del gráfico de medias: Las barras con colores cálidos (rojo/naranja) corresponden a ítems donde los estudiantes tienden al desacuerdo o incertidumbre; las barras verdes reflejan acuerdo. La línea punteada en 3.0 es el punto neutro. Si la mayoría de ítems de una dimensión superan ese umbral, la tendencia general de la facultad es favorable hacia esa dimensión de la energía nuclear.
dims <- datos %>% select(D1_conocimiento, D2_riesgo, D3_actitud, D4_influencia,
D5_comparacion, puntaje_total)
desc_dim <- data.frame(
Dimensión = c("D1 Conocimiento/Conciencia",
"D2 Percepción de Riesgo",
"D3 Actitud Favorable",
"D4 Influencia Mediática/Formativa",
"D5 Comparación de Riesgos",
"Puntaje Total"),
n = colSums(!is.na(dims)),
Media = round(colMeans(dims, na.rm = TRUE), 2),
DE = round(apply(dims, 2, sd, na.rm = TRUE), 2),
Mín = round(apply(dims, 2, min, na.rm = TRUE), 2),
Mediana = round(apply(dims, 2, median, na.rm = TRUE), 2),
Máx = round(apply(dims, 2, max, na.rm = TRUE), 2)
)
kable(desc_dim, caption = "Tabla 6. Estadísticos descriptivos por dimensión",
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(6, bold = TRUE, background = "#eaf4fb")| Dimensión | n | Media | DE | Mín | Mediana | Máx |
|---|---|---|---|---|---|---|
| D1 Conocimiento/Conciencia | 234 | 3.47 | 0.99 | 1 | 3.50 | 5 |
| D2 Percepción de Riesgo | 234 | 3.37 | 0.98 | 1 | 3.33 | 5 |
| D3 Actitud Favorable | 234 | 3.53 | 1.00 | 1 | 3.67 | 5 |
| D4 Influencia Mediática/Formativa | 234 | 2.99 | 0.89 | 1 | 3.00 | 5 |
| D5 Comparación de Riesgos | 234 | 3.19 | 0.98 | 1 | 3.17 | 5 |
| Puntaje Total | 234 | 3.35 | 0.79 | 1 | 3.45 | 5 |
📊 Interpretación por dimensiones: Compara las medias de cada dimensión con el punto neutro (3.0): - D1 Conocimiento > 3 → los estudiantes reconocen aspectos científicos básicos de la energía nuclear. - D2 Riesgo > 3 → perciben los riesgos como altos — actitud de precaución predominante. - D3 Actitud > 3 → tendencia favorable hacia aplicaciones y potencial de la energía nuclear. - D4 Influencia > 3 → los medios y la formación académica sí moldean su opinión. - D5 Comparación → evalúa si relativizan el riesgo nuclear frente a otros riesgos cotidianos.
Una D3 alta con D2 también alta es un hallazgo clave: significa que los estudiantes reconocen el potencial de la energía nuclear a pesar de percibirla como riesgosa — ambivalencia actitudinal frecuente en este tipo de estudios.
# ── Alfa global ────────────────────────────────────────────────────────────────
alfa_global <- psych::alpha(items, na.rm = TRUE)
cat("=== ALFA DE CRONBACH — ESCALA COMPLETA (P1–P20) ===\n")## === ALFA DE CRONBACH — ESCALA COMPLETA (P1–P20) ===
## α = 0.934
## α estandarizado = 0.935
## Correlación media inter-ítems = 0.418
cat(sprintf(" IC 95%%: [%.3f, %.3f]\n\n",
alfa_global$total$raw_alpha - 1.96 * alfa_global$total$ase,
alfa_global$total$raw_alpha + 1.96 * alfa_global$total$ase))## IC 95%: [0.922, 0.946]
# ── Interpretación ─────────────────────────────────────────────────────────────
alpha_val <- alfa_global$total$raw_alpha
interpretacion <- dplyr::case_when(
alpha_val >= 0.90 ~ "Excelente (≥ 0.90)",
alpha_val >= 0.80 ~ "Bueno (0.80–0.89)",
alpha_val >= 0.70 ~ "Aceptable (0.70–0.79)",
alpha_val >= 0.60 ~ "Cuestionable (0.60–0.69)",
alpha_val >= 0.50 ~ "Deficiente (0.50–0.59)",
TRUE ~ "Inaceptable (< 0.50)"
)
cat(sprintf(" Interpretación: %s\n\n", interpretacion))## Interpretación: Excelente (≥ 0.90)
# ── Alfa por dimensión ─────────────────────────────────────────────────────────
alfa_dim <- list(
D1_Conocimiento = psych::alpha(datos %>% select(P1:P4), na.rm = TRUE),
D2_Riesgo = psych::alpha(datos %>% select(P5, P7, P9), na.rm = TRUE),
D3_Actitud = psych::alpha(datos %>% select(P6, P10, P11, P12, P13, P14),
na.rm = TRUE),
D4_Influencia = psych::alpha(datos %>% select(P15, P16, P17), na.rm = TRUE),
D5_Comparacion = psych::alpha(datos %>% select(P18, P19, P20), na.rm = TRUE)
)
tabla_alfa <- data.frame(
Dimensión = c("D1 Conocimiento (P1–P4)",
"D2 Percepción de riesgo (P5, P7, P9)",
"D3 Actitud favorable (P6, P10–P14)",
"D4 Influencia mediática (P15–P17)",
"D5 Comparación de riesgos (P18–P20)",
"Escala completa (P1–P20)"),
Ítems = c(4, 3, 6, 3, 3, 20),
Alpha = round(c(
alfa_dim$D1_Conocimiento$total$raw_alpha,
alfa_dim$D2_Riesgo$total$raw_alpha,
alfa_dim$D3_Actitud$total$raw_alpha,
alfa_dim$D4_Influencia$total$raw_alpha,
alfa_dim$D5_Comparacion$total$raw_alpha,
alfa_global$total$raw_alpha
), 3),
Interpretacion = c(
ifelse(alfa_dim$D1_Conocimiento$total$raw_alpha >= 0.70, "Aceptable o superior", "Cuestionable"),
ifelse(alfa_dim$D2_Riesgo$total$raw_alpha >= 0.70, "Aceptable o superior", "Cuestionable"),
ifelse(alfa_dim$D3_Actitud$total$raw_alpha >= 0.70, "Aceptable o superior", "Cuestionable"),
ifelse(alfa_dim$D4_Influencia$total$raw_alpha >= 0.70, "Aceptable o superior", "Cuestionable"),
ifelse(alfa_dim$D5_Comparacion$total$raw_alpha >= 0.70, "Aceptable o superior", "Cuestionable"),
interpretacion
)
)
kable(tabla_alfa,
caption = "Tabla 7. Coeficiente alfa de Cronbach por dimensión",
col.names = c("Dimensión", "Ítems", "α de Cronbach", "Interpretación"),
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(6, bold = TRUE, background = "#d5f5e3")| Dimensión | Ítems | α de Cronbach | Interpretación |
|---|---|---|---|
| D1 Conocimiento (P1–P4) | 4 | 0.837 | Aceptable o superior |
| D2 Percepción de riesgo (P5, P7, P9) | 3 | 0.697 | Cuestionable |
| D3 Actitud favorable (P6, P10–P14) | 6 | 0.926 | Aceptable o superior |
| D4 Influencia mediática (P15–P17) | 3 | 0.587 | Cuestionable |
| D5 Comparación de riesgos (P18–P20) | 3 | 0.831 | Aceptable o superior |
| Escala completa (P1–P20) | 20 | 0.934 | Excelente (≥ 0.90) |
📊 Interpretación del Alfa de Cronbach: El alfa de Cronbach mide la consistencia interna del instrumento — qué tan bien miden los ítems el mismo constructo. Criterios de George & Mallery (2003):
α Interpretación ≥ 0.90 Excelente 0.80–0.89 Bueno 0.70–0.79 Aceptable ✓ mínimo recomendado 0.60–0.69 Cuestionable < 0.60 Inaceptable Si el α global ≥ 0.70, el instrumento es válido y confiable para los análisis siguientes. Para las dimensiones, valores por encima de 0.60 son aceptables dado que tienen pocos ítems (3–6). En la tabla de ítem-total, si eliminar un ítem aumenta mucho el α, considera reportarlo como ítem problemático en tu discusión.
# Correlaciones ítem-total corregidas
item_total <- round(alfa_global$item.stats[, c("r.cor", "r.drop")], 3)
colnames(item_total) <- c("r.cor corregida", "alpha si elimina item")
item_total$Item <- paste0("P", 1:20)
item_total <- item_total[, c("Item", "r.cor corregida", "alpha si elimina item")]
kable(item_total,
caption = "Tabla 8. Estadísticos ítem-total (correlaciones y alfa si se elimina)",
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "condensed"), full_width = FALSE)| Item | r.cor corregida | alpha si elimina item |
|---|---|---|
| P1 | 0.698 | 0.674 |
| P2 | 0.737 | 0.711 |
| P3 | 0.701 | 0.673 |
| P4 | 0.687 | 0.665 |
| P5 | 0.327 | 0.295 |
| P6 | 0.701 | 0.678 |
| P7 | 0.587 | 0.564 |
| P8 | 0.689 | 0.663 |
| P9 | 0.491 | 0.465 |
| P10 | 0.819 | 0.791 |
| P11 | 0.788 | 0.752 |
| P12 | 0.811 | 0.777 |
| P13 | 0.772 | 0.739 |
| P14 | 0.759 | 0.733 |
| P15 | 0.347 | 0.327 |
| P16 | 0.526 | 0.501 |
| P17 | 0.530 | 0.508 |
| P18 | 0.736 | 0.707 |
| P19 | 0.729 | 0.696 |
| P20 | 0.602 | 0.577 |
📊 Interpretación correlaciones ítem-total: Las correlaciones ítem-total corregidas (columna r.cor corregida) deben ser ≥ 0.30 para considerar que el ítem contribuye al constructo. Ítems con correlación < 0.20 son candidatos a revisión o eliminación. La columna alpha si elimina item te dice cuánto cambiaría la confiabilidad si quitaras ese ítem — si al eliminarlo el α sube notablemente, ese ítem es discordante con el resto de la escala.
## === PRUEBA DE NORMALIDAD (Shapiro-Wilk) ===
vars_test <- c("puntaje_total", "D1_conocimiento", "D2_riesgo",
"D3_actitud", "D4_influencia", "D5_comparacion")
res_norm <- lapply(vars_test, function(v) {
x <- na.omit(datos[[v]])
sw <- shapiro.test(x)
data.frame(Variable = v,
W = round(sw$statistic, 4),
p_valor = round(sw$p.value, 4),
Normal = ifelse(sw$p.value > 0.05, "Sí (p > .05)", "No (p ≤ .05)"))
})
tab_norm <- do.call(rbind, res_norm)
kable(tab_norm, row.names = FALSE,
caption = "Tabla 9. Pruebas de normalidad Shapiro-Wilk") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Variable | W | p_valor | Normal |
|---|---|---|---|
| puntaje_total | 0.9437 | 0e+00 | No (p ≤ .05) |
| D1_conocimiento | 0.9514 | 0e+00 | No (p ≤ .05) |
| D2_riesgo | 0.9483 | 0e+00 | No (p ≤ .05) |
| D3_actitud | 0.9498 | 0e+00 | No (p ≤ .05) |
| D4_influencia | 0.9741 | 3e-04 | No (p ≤ .05) |
| D5_comparacion | 0.9681 | 0e+00 | No (p ≤ .05) |
📊 Interpretación Shapiro-Wilk: Si p > 0.05 → no se rechaza normalidad → se pueden usar pruebas paramétricas (ANOVA, t). Si p ≤ 0.05 → se viola el supuesto → usar pruebas no paramétricas (Kruskal-Wallis, Mann-Whitney). Con n = 234, el teorema del límite central garantiza que las medias son aproximadamente normales incluso si los datos individuales no lo son, por lo que el ANOVA sigue siendo robusto. En el documento se reportan ambas pruebas (paramétrica y no paramétrica) para mayor rigor.
par(mfrow = c(2, 3))
for (v in vars_test) {
qqnorm(na.omit(datos[[v]]), main = paste("Q-Q:", v), pch = 19, cex = 0.6)
qqline(na.omit(datos[[v]]), col = "firebrick", lwd = 2)
}📊 Interpretación gráficos Q-Q: Los puntos deben seguir la línea diagonal roja. Desviaciones en los extremos (colas) son comunes con datos Likert y no invalidan el análisis con n > 100. Si los puntos forman una “S”, indica distribución platicúrtica; si se separan en los extremos, indica colas pesadas.
## === PRUEBA DE LEVENE — Homogeneidad de varianzas ===
lev_prog <- car::leveneTest(puntaje_total ~ programa, data = datos)
lev_sexo <- car::leveneTest(puntaje_total ~ sexo, data = datos)
cat("Por programa:", "\n")## Por programa:
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 2 3.6847 0.02659 *
## 231
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Por sexo:
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 1 0.0495 0.8242
## 232
📊 Interpretación Levene: Si p > 0.05 → varianzas homogéneas → ANOVA estándar es apropiado. Si p ≤ 0.05 → varianzas heterogéneas → usar Welch-ANOVA o pruebas no paramétricas. En la prueba t de sexo ya se usa
var.equal = FALSE(t de Welch) como precaución.
H₀: Los puntajes medios de tendencia de pensamiento
son iguales en los tres programas.
H₁: Al menos un programa difiere en el puntaje
medio.
## === H1: ANOVA de un factor — Puntaje total por programa ===
# Si se cumple normalidad → ANOVA; si no → Kruskal-Wallis
anova_prog <- aov(puntaje_total ~ programa, data = datos)
sum_anova <- summary(anova_prog)
print(sum_anova)## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 8.62 4.309 7.23 9e-04 ***
## Residuals 231 137.66 0.596
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\nTamaño del efecto (η²):",
round(sum_anova[[1]][["Sum Sq"]][1] /
sum(sum_anova[[1]][["Sum Sq"]]), 3), "\n")##
## Tamaño del efecto (η²): 0.059
# Post hoc Tukey HSD
tukey <- TukeyHSD(anova_prog)
kable(as.data.frame(tukey$programa) %>%
mutate(across(where(is.numeric), ~ round(., 4))),
caption = "Tabla 10. Comparaciones post hoc Tukey HSD (puntaje por programa)") %>%
kable_styling(bootstrap_options = c("striped"), full_width = FALSE)| diff | lwr | upr | p adj | |
|---|---|---|---|---|
| Física-Biología | 0.3790 | 0.0684 | 0.6896 | 0.0121 |
| Matemática Aplicada-Biología | -0.2059 | -0.5028 | 0.0911 | 0.2328 |
| Matemática Aplicada-Física | -0.5849 | -0.9535 | -0.2163 | 0.0007 |
📊 Interpretación H1 — Post hoc Tukey: - Si el ANOVA es significativo (p < 0.05), al menos un programa difiere de los demás. - El Tukey HSD identifica cuáles pares difieren. Busca en la tabla las comparaciones con
p adj < 0.05. - Interpretación sustantiva: Si Física difiere de Biología y Matemática, significa que la formación disciplinar específica (variable formativa) genera tendencias de pensamiento distintas — resultado central para tu objetivo específico 2 (relación entre planes de estudio y tendencias). - El η² (eta cuadrado) indica el tamaño del efecto: < 0.06 pequeño, 0.06–0.14 mediano, > 0.14 grande.
# Kruskal-Wallis como prueba no paramétrica complementaria
kw <- kruskal.test(puntaje_total ~ programa, data = datos)
cat("Kruskal-Wallis H =", round(kw$statistic, 3),
" gl =", kw$parameter,
" p =", round(kw$p.value, 4), "\n")## Kruskal-Wallis H = 20.691 gl = 2 p = 0
📊 Kruskal-Wallis: Confirma el ANOVA con datos ordinales. Si ambas pruebas coinciden en la conclusión (ambas p < 0.05 o ambas p > 0.05), el resultado es robusto. Si difieren, reporta el Kruskal-Wallis como prueba principal dado que los datos Likert son ordinales.
ggplot(datos, aes(x = programa, y = puntaje_total, fill = programa)) +
geom_boxplot(alpha = 0.7, outlier.shape = 21) +
geom_jitter(width = 0.15, alpha = 0.3, size = 1.2) +
stat_summary(fun = mean, geom = "point", shape = 23, size = 3,
fill = "white", color = "black") +
scale_fill_manual(values = c("#2196F3", "#FF5722", "#4CAF50")) +
labs(title = "H1: Puntaje total por programa académico",
subtitle = "◆ = media aritmética",
x = "Programa", y = "Puntaje promedio (1–5)") +
theme_minimal(base_size = 12) + theme(legend.position = "none")📊 Interpretación boxplot H1: Observa si las cajas de los tres programas se solapan o están separadas. Poco solapamiento y medianas distintas refuerzan visualmente la significancia estadística. El rombo (◆) muestra la media — si difiere mucho de la mediana, hay asimetría en ese grupo.
H₀: No existen diferencias en el puntaje total entre
hombres y mujeres.
H₁: Existen diferencias significativas por sexo.
## === H2: Prueba t — Puntaje total por sexo ===
##
## Welch Two Sample t-test
##
## data: puntaje_total by sexo
## t = -4.1841, df = 231.99, p-value = 4.063e-05
## alternative hypothesis: true difference in means between group Femenino and group Masculino is not equal to 0
## 95 percent confidence interval:
## -0.6156433 -0.2214619
## sample estimates:
## mean in group Femenino mean in group Masculino
## 3.137281 3.555833
# Tamaño del efecto d de Cohen
medias <- tapply(datos$puntaje_total, datos$sexo, mean, na.rm = TRUE)
sds <- tapply(datos$puntaje_total, datos$sexo, sd, na.rm = TRUE)
ns <- tapply(datos$puntaje_total, datos$sexo, function(x) sum(!is.na(x)))
sp <- sqrt(((ns[1]-1)*sds[1]^2 + (ns[2]-1)*sds[2]^2) / (sum(ns) - 2))
d_cohen <- abs(diff(medias)) / sp
cat("\nd de Cohen:", round(d_cohen, 3),
" Interpretación:",
ifelse(d_cohen < 0.2, "trivial",
ifelse(d_cohen < 0.5, "pequeño",
ifelse(d_cohen < 0.8, "mediano", "grande"))), "\n")##
## d de Cohen: 0.547 Interpretación: mediano
📊 Interpretación H2 — Sexo: - Si p < 0.05: existe diferencia estadísticamente significativa por sexo en la tendencia de pensamiento sobre energía nuclear. - La d de Cohen cuantifica la magnitud: < 0.2 trivial, 0.2–0.5 pequeño, 0.5–0.8 mediano, > 0.8 grande. - En estudios de percepción de riesgo tecnológico, es frecuente que las mujeres puntúen más alto en percepción de riesgo y más bajo en actitud favorable — si eso ocurre aquí, constituye evidencia para tu objetivo 3 (correlación con variables socioculturales).
# Mann-Whitney U (no paramétrico)
mw <- wilcox.test(puntaje_total ~ sexo, data = datos)
cat("Mann-Whitney U =", mw$statistic,
" p =", round(mw$p.value, 4), "\n")## Mann-Whitney U = 4359.5 p = 0
H₀: El puntaje total no varía significativamente
entre grupos de edad.
H₁: Al menos un grupo de edad difiere en su
puntaje.
## === H3: ANOVA y Kruskal-Wallis — Puntaje total por edad ===
## Df Sum Sq Mean Sq F value Pr(>F)
## edad 4 7.09 1.7722 2.916 0.0222 *
## Residuals 229 139.19 0.6078
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
kw_edad <- kruskal.test(puntaje_total ~ edad, data = datos)
cat("\nKruskal-Wallis H =", round(kw_edad$statistic, 3),
" p =", round(kw_edad$p.value, 4), "\n")##
## Kruskal-Wallis H = 8.844 p = 0.0651
📊 Interpretación H3 — Edad: - Si p < 0.05: la edad (variable sociocultural) predice diferencias en las tendencias de pensamiento. - Esperable que estudiantes de mayor edad y semestres avanzados tengan más conocimiento (D1 mayor) y actitudes más matizadas (D3 moderada). Si el patrón es contrario, es un hallazgo interesante para discutir. - Si no hay diferencias significativas por edad, reporta que las tendencias son homogéneas entre generaciones dentro de la facultad.
H₀: Los vectores de medias dimensionales son iguales
entre programas.
H₁: Al menos un programa difiere en al menos una
dimensión.
## === H4: MANOVA — Dimensiones × Programa ===
manova_fit <- manova(
cbind(D1_conocimiento, D2_riesgo, D3_actitud,
D4_influencia, D5_comparacion) ~ programa,
data = datos
)
print(summary(manova_fit, test = "Pillai"))## Df Pillai approx F num Df den Df Pr(>F)
## programa 2 0.17319 4.3231 10 456 8.613e-06 ***
## Residuals 231
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Response D1_conocimiento :
## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 21.842 10.921 12.243 8.837e-06 ***
## Residuals 231 206.054 0.892
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response D2_riesgo :
## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 8.877 4.4386 4.8182 0.008912 **
## Residuals 231 212.802 0.9212
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response D3_actitud :
## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 16.537 8.2685 8.8619 0.0001958 ***
## Residuals 231 215.532 0.9330
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response D4_influencia :
## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 0.403 0.20159 0.2528 0.7769
## Residuals 231 184.233 0.79755
##
## Response D5_comparacion :
## Df Sum Sq Mean Sq F value Pr(>F)
## programa 2 4.486 2.24324 2.3397 0.09864 .
## Residuals 231 221.476 0.95877
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
📊 Interpretación H4 — MANOVA: - El estadístico de Pillai (preferido cuando se viola normalidad multivariada) evalúa si los programas difieren simultáneamente en las cinco dimensiones. - Si p < 0.05 en Pillai: hay diferencias multivariadas → mira los ANOVAs univariados por dimensión (segunda parte del output) para identificar en cuáles dimensiones específicamente difieren los programas. - Esto responde directamente al objetivo específico 2: la relación entre el plan de estudios y las tendencias por área temática.
H₀: No existe correlación significativa entre el semestre y las dimensiones.
## === H5: Correlación semestre × dimensiones ===
vars_cor <- c("D1_conocimiento", "D2_riesgo", "D3_actitud",
"D4_influencia", "D5_comparacion", "puntaje_total")
res_cor <- lapply(vars_cor, function(v) {
ct <- cor.test(datos$semestre, datos[[v]], method = "spearman",
use = "complete.obs")
data.frame(Variable = v,
rho = round(ct$estimate, 3),
p_valor = round(ct$p.value, 4),
Sig = ifelse(ct$p.value < 0.001, "***",
ifelse(ct$p.value < 0.01, "**",
ifelse(ct$p.value < 0.05, "*", "ns"))))
})
tab_cor <- do.call(rbind, res_cor)
kable(tab_cor, row.names = FALSE,
caption = "Tabla 11. Correlaciones Spearman semestre × dimensiones") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
column_spec(4, bold = TRUE)| Variable | rho | p_valor | Sig |
|---|---|---|---|
| D1_conocimiento | 0.326 | 0.0000 | *** |
| D2_riesgo | 0.080 | 0.2199 | ns |
| D3_actitud | 0.252 | 0.0001 | *** |
| D4_influencia | 0.140 | 0.0326 |
|
| D5_comparacion | 0.149 | 0.0226 |
|
| puntaje_total | 0.275 | 0.0000 | *** |
📊 Interpretación H5 — Correlación Spearman semestre × dimensiones: - ρ (rho) mide la correlación: +1 correlación positiva perfecta, −1 negativa perfecta, 0 sin correlación. - Si ρ > 0 y p < 0.05 en D1 (conocimiento): a mayor semestre, mayor conocimiento percibido sobre energía nuclear — coherente con la formación académica acumulada. - Si ρ > 0 en D3 (actitud favorable): los estudiantes de semestres avanzados son más favorables a la energía nuclear, posiblemente por mayor exposición a ciencia básica. - Una correlación significativa aquí responde al objetivo específico 3 y aporta evidencia directa a la pregunta de investigación.
Modelo:
puntaje_total ~ semestre + programa + sexo + edad
## === H6: Regresión múltiple (OLS) ===
##
## Call:
## lm(formula = puntaje_total ~ semestre + programa + sexo + edad,
## data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.40671 -0.27649 0.08617 0.43901 1.82116
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.77686 0.15923 17.439 < 2e-16 ***
## semestre 0.04995 0.02010 2.486 0.0137 *
## programaFísica 0.20831 0.13503 1.543 0.1243
## programaMatemática Aplicada -0.20348 0.13279 -1.532 0.1268
## sexoMasculino 0.42805 0.10212 4.192 3.98e-05 ***
## edad18 – 22 0.15551 0.16448 0.945 0.3454
## edad23 – 27 0.04402 0.20653 0.213 0.8314
## edad28 – 32 0.17558 0.26510 0.662 0.5084
## edadMás de 32 -0.51918 0.38140 -1.361 0.1748
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.7316 on 225 degrees of freedom
## Multiple R-squared: 0.1768, Adjusted R-squared: 0.1475
## F-statistic: 6.038 on 8 and 225 DF, p-value: 4.921e-07
##
## Análisis de varianza del modelo:
## Analysis of Variance Table
##
## Response: puntaje_total
## Df Sum Sq Mean Sq F value Pr(>F)
## semestre 1 9.670 9.6704 18.0679 3.124e-05 ***
## programa 2 4.100 2.0500 3.8301 0.02314 *
## sexo 1 9.295 9.2953 17.3670 4.395e-05 ***
## edad 4 2.790 0.6974 1.3030 0.26978
## Residuals 225 120.426 0.5352
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
📊 Interpretación H6 — Regresión múltiple: Este modelo responde directamente la pregunta de investigación: ¿en qué medida las variables socioculturales y formativas predicen las tendencias de pensamiento?
- R² ajustado: proporción de varianza del puntaje total explicada por el modelo. R² > 0.10 ya es relevante en ciencias sociales; R² > 0.25 es bueno.
- Coeficientes significativos (p < 0.05): las variables con asterisco (*) son predictores estadísticamente relevantes.
- Interpretación de coeficientes: el signo (+/−) indica la dirección. Ej: si
programaFísicatiene coeficiente positivo significativo, los estudiantes de Física puntúan más alto que la categoría de referencia (Biología).- Modelo general (F-test): si el p-valor global es < 0.05, el conjunto de predictores explica varianza real — el modelo es útil.
- Si el R² es bajo (< 0.10), no significa que la investigación sea inválida — significa que hay otras variables no medidas que también influyen (cultura, medios, experiencias previas), lo cual puedes discutir como limitación y línea futura.
📊 Gráficos diagnósticos del modelo de regresión: - Residuals vs Fitted: los residuos deben distribuirse aleatoriamente alrededor del 0. Patrones en abanico = heterocedasticidad. - Q-Q de residuos: los puntos deben seguir la diagonal. Desviaciones en colas son tolerables con n > 200. - Scale-Location: evalúa homocedasticidad; la línea debe ser horizontal. - Cook’s Distance / Leverage: puntos > 0.5 en Cook’s D son observaciones influyentes que conviene investigar.
## Factor de inflación de varianza (VIF):
## GVIF Df GVIF^(1/(2*Df))
## semestre 1.630 1 1.277
## programa 1.459 2 1.099
## sexo 1.139 1 1.067
## edad 1.649 4 1.065
📊 VIF — Multicolinealidad: Valores VIF > 5 indican colinealidad problemática entre predictores. Si todos los VIF < 5, los predictores son suficientemente independientes y los coeficientes del modelo son estables e interpretables.
datos_long <- datos %>%
select(programa, D1_conocimiento, D2_riesgo, D3_actitud,
D4_influencia, D5_comparacion) %>%
pivot_longer(-programa,
names_to = "Dimensión",
values_to = "Puntaje") %>%
mutate(Dimensión = case_match(Dimensión,
"D1_conocimiento" ~ "D1 Conocimiento",
"D2_riesgo" ~ "D2 Riesgo",
"D3_actitud" ~ "D3 Actitud",
"D4_influencia" ~ "D4 Influencia",
"D5_comparacion" ~ "D5 Comparación"
))
ggplot(datos_long, aes(x = Dimensión, y = Puntaje, fill = programa)) +
geom_boxplot(alpha = 0.75, outlier.alpha = 0.3) +
stat_summary(fun = mean, geom = "point", shape = 23, size = 2,
position = position_dodge(0.75), fill = "white") +
scale_fill_manual(values = c("#2196F3", "#FF5722", "#4CAF50"),
name = "Programa") +
labs(title = "Distribución de dimensiones por programa académico",
subtitle = "◆ = media | Escala Likert 1–5",
x = NULL, y = "Puntaje promedio") +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")📊 Interpretación boxplot por dimensión y programa: Este gráfico es uno de los más informativos del estudio. Permite ver de un vistazo en qué dimensiones difieren los programas: - Si las cajas de Física están claramente por encima de Biología y Matemática en D1 (conocimiento) y D3 (actitud), confirma que la formación en física nuclear genera mayor conocimiento y actitud más favorable. - Si Biología puntúa más alto en D2 (riesgo), puede reflejar una mayor sensibilidad ambiental por su perfil de carrera. - La ausencia de diferencias en alguna dimensión también es un resultado: indicaría que esa percepción es transversal a todos los programas.
tab_dim_prog <- datos %>%
group_by(programa) %>%
summarise(
`D1 Conocimiento` = round(mean(D1_conocimiento, na.rm = TRUE), 2),
`D2 Riesgo` = round(mean(D2_riesgo, na.rm = TRUE), 2),
`D3 Actitud` = round(mean(D3_actitud, na.rm = TRUE), 2),
`D4 Influencia` = round(mean(D4_influencia, na.rm = TRUE), 2),
`D5 Comparación` = round(mean(D5_comparacion, na.rm = TRUE), 2),
`Total` = round(mean(puntaje_total, na.rm = TRUE), 2),
.groups = "drop"
)
kable(tab_dim_prog,
caption = "Tabla 12. Medias por dimensión según programa académico") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| programa | D1 Conocimiento | D2 Riesgo | D3 Actitud | D4 Influencia | D5 Comparación | Total |
|---|---|---|---|---|---|---|
| Biología | 3.40 | 3.47 | 3.48 | 2.99 | 3.11 | 3.32 |
| Física | 4.05 | 3.49 | 4.02 | 3.06 | 3.46 | 3.70 |
| Matemática Aplicada | 3.14 | 3.01 | 3.22 | 2.93 | 3.15 | 3.12 |
📊 Interpretación tabla de medias por programa: Compara fila a fila los tres programas. Las diferencias numéricas > 0.30 entre programas en una misma dimensión son sustancialmente relevantes. La columna Total resume la tendencia global de cada programa.
mat_cor <- datos %>%
select(P1:P20) %>%
cor(use = "complete.obs")
corrplot::corrplot(mat_cor,
method = "color",
type = "upper",
tl.cex = 0.7,
tl.col = "black",
addCoef.col = "black",
number.cex = 0.45,
col = colorRampPalette(c("#f44336","white","#2196F3"))(200),
title = "Matriz de correlaciones — Ítems P1–P20",
mar = c(0, 0, 2, 0))📊 Interpretación mapa de calor: - Azul intenso (r cercano a +1): los dos ítems se mueven juntos — los estudiantes que están de acuerdo con uno tienden a estarlo con el otro. - Rojo intenso (r cercano a −1): relación inversa — acuerdo con uno implica desacuerdo con el otro. - Bloques de correlaciones altas entre ítems de una misma dimensión (ej. P1–P4) validan que la agrupación dimensional es coherente. - Correlaciones bajas entre dimensiones confirman que las dimensiones miden constructos distintos (validez discriminante). - Ítems que correlacionan muy poco con todos los demás (fila/columna sin azul ni rojo) son candidatos a revisar en futuras versiones del instrumento.
# Frecuencias relativas por ítem
freq_likert <- datos %>%
select(P1:P20) %>%
pivot_longer(everything(), names_to = "Item", values_to = "Respuesta") %>%
filter(!is.na(Respuesta)) %>%
group_by(Item, Respuesta) %>%
summarise(n = n(), .groups = "drop") %>%
group_by(Item) %>%
mutate(Porcentaje = n / sum(n) * 100) %>%
ungroup() %>%
mutate(Respuesta = factor(Respuesta, levels = 1:5,
labels = c("1\nTot. desacuerdo",
"2\nDesacuerdo",
"3\nNeutro",
"4\nDe acuerdo",
"5\nTot. acuerdo")))
ggplot(freq_likert, aes(x = Item, y = Porcentaje, fill = Respuesta)) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(
values = c("#d32f2f","#ef9a9a","#FFF9C4","#a5d6a7","#388e3c"),
name = "Respuesta") +
scale_y_continuous(labels = percent_format()) +
coord_flip() +
labs(title = "Distribución de respuestas Likert por ítem",
x = NULL, y = "Proporción de respuestas") +
theme_minimal(base_size = 11) +
theme(legend.position = "bottom")📊 Interpretación gráfico de barras apiladas: Este gráfico muestra la distribución completa de respuestas para cada ítem. Los colores verdes representan acuerdo (4 y 5), el amarillo es neutro (3), y los rojos son desacuerdo (1 y 2). - Ítems con barra mayoritariamente verde: consenso de acuerdo en la muestra. - Ítems con barras divididas entre verde y rojo con poco amarillo: alta polarización — los estudiantes tienen opiniones fuertes pero opuestas. Esto es especialmente relevante para tu análisis cualitativo. - Ítems con amarillo dominante: alta indecisión o desconocimiento del tema — posible señal de que el ítem es ambiguo o que el tema es desconocido para ese grupo.
## ╔══════════════════════════════════════════════════════════════════╗
## ║ RESUMEN DE RESULTADOS ESTADÍSTICOS ║
## ╠══════════════════════════════════════════════════════════════════╣
cat(sprintf("║ α de Cronbach (escala completa): %.3f (%s) ║\n",
alfa_global$total$raw_alpha, interpretacion))## ║ α de Cronbach (escala completa): 0.934 (Excelente (≥ 0.90)) ║
cat(sprintf("║ n = %d | Biología: %d | Física: %d | Mat. Ap.: %d ║\n",
nrow(datos), sum(datos$programa=="Biología"),
sum(datos$programa=="Física"),
sum(datos$programa=="Matemática Aplicada")))## ║ n = 234 | Biología: 136 | Física: 46 | Mat. Ap.: 52 ║
## ╚══════════════════════════════════════════════════════════════════╝
resumen_h <- data.frame(
Hipótesis = c("H1: Diferencias por programa (ANOVA)",
"H2: Diferencias por sexo (t / Mann-Whitney)",
"H3: Diferencias por edad (ANOVA / Kruskal)",
"H4: Diferencias multivariadas (MANOVA)",
"H5: Correlación semestre–dimensiones (Spearman)",
"H6: Regresión múltiple (OLS)"),
Prueba = c("ANOVA + Tukey HSD + Kruskal-Wallis",
"t de Welch + Mann-Whitney U",
"ANOVA + Kruskal-Wallis",
"MANOVA (Pillai)",
"Spearman ρ",
"Regresión lineal múltiple"),
Decisión = c("Ver output arriba", "Ver output arriba",
"Ver output arriba", "Ver output arriba",
"Ver output arriba", "Ver output arriba")
)
kable(resumen_h,
caption = "Tabla 13. Resumen de pruebas de hipótesis del estudio") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Hipótesis | Prueba | Decisión |
|---|---|---|
| H1: Diferencias por programa (ANOVA) | ANOVA + Tukey HSD + Kruskal-Wallis | Ver output arriba |
| H2: Diferencias por sexo (t / Mann-Whitney) | t de Welch + Mann-Whitney U | Ver output arriba |
| H3: Diferencias por edad (ANOVA / Kruskal) | ANOVA + Kruskal-Wallis | Ver output arriba |
| H4: Diferencias multivariadas (MANOVA) | MANOVA (Pillai) | Ver output arriba |
| H5: Correlación semestre–dimensiones (Spearman) | Spearman ρ | Ver output arriba |
| H6: Regresión múltiple (OLS) | Regresión lineal múltiple | Ver output arriba |
A continuación se presentan las conclusiones derivadas del análisis:
Fiabilidad del instrumento: El coeficiente alfa de Cronbach para la escala completa (20 ítems) permite determinar el nivel de consistencia interna del instrumento. Valores ≥ 0.70 son considerados aceptables para investigación en ciencias sociales (George & Mallery, 2003).
Perfil de la muestra: La muestra estratificada (n = 234) representa fielmente las proporciones poblacionales de los tres programas: Biología (58.1 %), Física (19.7 %) y Matemática Aplicada (22.2 %).
Tendencias de pensamiento: Los puntajes promedio por dimensión revelan los patrones actitudinales predominantes. Valores > 3 indican acuerdo; valores < 3 indican desacuerdo con los enunciados.
Diferencias por programa: El ANOVA/Kruskal-Wallis permite evaluar si el programa académico (variable formativa) predice diferencias en las tendencias de pensamiento, respondiendo al objetivo específico 3.
Predicción del puntaje total: El modelo de regresión múltiple (H6) estima en qué medida las variables socioculturales (sexo, edad) y formativas (semestre, programa) predicen conjuntamente la tendencia de pensamiento, respondiendo directamente a la pregunta de investigación.
Documento generado automáticamente con R Markdown. Para
reproducir, asegúrese de que el archivo de datos
Cuestionario_final__respuestas.xlsx se encuentre en el
mismo directorio de trabajo.