📚 Librería
library(readxl)
library(glue)
library(dplyr)
library(psych)
library(ggplot2)
library(knitr)
library(janitor)
library(nortest)
library(kableExtra)
library(tidyr)
library(ggrepel)
library(tidyverse)
library(effsize)
library(purrr)
❓Preguntas de investigación
Pregunta de investigación general
¿Qué relación existe entre la participación en un voluntariado
curricular y el desarrollo de conductas prosociales en estudiantes
universitarios?
Pregunta de investigación cuantitativa
¿Existe una diferencia significativa en los niveles de prosocialidad de
los estudiantes universitarios antes y después de participar en un
voluntariado curricular, medida con la escala de prosocialidad para
adultos de Caprara?
📥 Importar y limpiar datos
# --- 1. Cargar el conjunto de datos ---
path_cuanti <- ("/Users/adrianaholguin/Desktop/Fase 2 cuanti.xlsx")
datos_pre_post_raw <- read_excel("/Users/adrianaholguin/Desktop/Fase 2 cuanti.xlsx")
# --- 2. Limpieza y Renombrado (transmute) ---
# (VERSIÓN FINAL: Solo importa los items. Los totales se calculan en el siguiente chunk)
datos_completos <- datos_pre_post_raw %>%
transmute(
Sujeto = as.character(Sujeto),
# --- Sociodemográficas ---
Edad = `X1..Edad`, Sexo = `X2..Sexo`, Estado_civil = `X3..Estado.civil`,
Trabaja = `X4..Trabaja`, Residente = `X5..Residente`, Vive_con = `X6..Vive.con`,
Grupo_vulnerabilidad = `X7..Grupo.de.vulnerabilidad`, Tipo_familia = `X8..Tipo.de.familia`,
Num_personas_casa = `X9..Numero.de.personas.que.habitan.la.casa.familiar`,
Nivel_socioeconomico = `X10..Nivel.socioeconomico.percibido`,
Involucramiento_familiar = `X11..Involucramiento.familiar.con.la.comunidad.percibido`,
Involucramiento_personal = `X12..Involucramiento.personal.con.su.comunidad.percibido`,
Gusto_voluntariado = `X13..Le.gustaria.realizar.voluntariados.en.sus.materias`,
Ha_voluntariado = `X15..Ha.realizado.voluntariados`,
# --- Items PRE-TEST (A) - Convertidos a numérico ---
A_item1 = as.numeric(`X27..A_Item1`), A_item2 = as.numeric(`X28..A_Item2`),
A_item3 = as.numeric(`X29..A_Item3`), A_item4 = as.numeric(`X30..A_Item4`),
A_item5 = as.numeric(`X31..A_Item5`), A_item6 = as.numeric(`X32..A_Item6`),
A_item7 = as.numeric(`X33..A_Item7`), A_item8 = as.numeric(`X34..A_Item8`),
A_item9 = as.numeric(`X35..A_Item9`), A_item10 = as.numeric(`X36..A_Item10`),
A_item11 = as.numeric(`X37..A_Item11`), A_item12 = as.numeric(`X38..A_Item12`),
A_item13 = as.numeric(`X39..A_Item13`), A_item14 = as.numeric(`X40..A_Item14`),
A_item15 = as.numeric(`X41..A_Item15`), A_item16 = as.numeric(`X42..A_Item16`),
# --- Items POST-TEST (B) - Convertidos a numérico ---
B_item1 = as.numeric(`X48..B_Item1`), B_item2 = as.numeric(`X49..B_Item2`),
B_item3 = as.numeric(`X50..B_Item3`), B_item4 = as.numeric(`X51..B_Item4`),
B_item5 = as.numeric(`52..B_Item5`), B_item6 = as.numeric(`X53..B_Item6`),
B_item7 = as.numeric(`X54..B_Item7`), B_item8 = as.numeric(`X55..B_Item8`),
B_item9 = as.numeric(`X56..B_Item9`), B_item10 = as.numeric(`X57..B_Item10`),
B_item11 = as.numeric(`X58..B_Item11`), B_item12 = as.numeric(`X59..B_Item12`),
B_item13 = as.numeric(`X60..B_Item13`), B_item14 = as.numeric(`X61..B_Item14`),
B_item15 = as.numeric(`X62..B_Item15`), B_item16 = as.numeric(`X63..B_Item16`)
)
cat("--- Carga de Datos Fase 2 (Solo Items) Completa ---\n")
## --- Carga de Datos Fase 2 (Solo Items) Completa ---
cat(paste("Datos (datos_completos) cargados con", nrow(datos_completos), "filas.\n"))
## Datos (datos_completos) cargados con 42 filas.
## --- Recálculo de Totales (Pre y Post) CORREGIDO ---
## Subescalas (Ayudar, Compartir, Empatia) recalculadas según su definición.
## Totales (Total_A, Total_B) recalculados con ítems 1 al 14.
1. 📊 Fiabilidad de la Escala (Post-test)
# Dimensión 1: Ayudar (6 items)
items_ayudar_b <- datos_completos %>%
select(B_item1, B_item3, B_item4, B_item6, B_item7, B_item13)
# Dimensión 2: Empatía (5 items)
items_empatia_b <- datos_completos %>%
select(B_item5, B_item8, B_item10, B_item12, B_item16)
# Dimensión 3: Compartir (3 items)
items_compartir_b <- datos_completos %>%
select(B_item2, B_item9, B_item14)
# Dimensión 4: Total (14 items)
items_total_b <- datos_completos %>%
select(
B_item1, B_item2, B_item3, B_item4, B_item5, B_item6, B_item7, B_item8, B_item9, B_item10, B_item11, B_item12, B_item13, B_item14 # Compartir
)
# --- 2. Calcular los 4 Alfas ---
alfa_ayudar <- psych::alpha(items_ayudar_b, check.keys = TRUE)
alfa_empatia <- psych::alpha(items_empatia_b, check.keys = TRUE)
alfa_compartir <- psych::alpha(items_compartir_b, check.keys = TRUE)
alfa_total <- psych::alpha(items_total_b, check.keys = TRUE)
# --- 3. Preparar la tabla para imprimir (con las 4 filas) ---
tabla_para_imprimir_alfa_post <- data.frame(
Dimension = c("Ayudar (Post)", "Empatía (Post)", "Compartir (Post)", "Escala Total (Post)"),
N_Items = c(
ncol(items_ayudar_b),
ncol(items_empatia_b),
ncol(items_compartir_b),
ncol(items_total_b)
),
Alfa_Cronbach = c(
alfa_ayudar$total$raw_alpha,
alfa_empatia$total$raw_alpha,
alfa_compartir$total$raw_alpha,
alfa_total$total$raw_alpha
)
)
Fiabilidad de la Escala (Alfa de Cronbach) - Post-test
|
Dimensión
|
N de Ítems
|
Alfa de Cronbach
|
|
Ayudar (Post)
|
6
|
0.633
|
|
Empatía (Post)
|
5
|
0.599
|
|
Compartir (Post)
|
3
|
0.357
|
|
Escala Total (Post)
|
14
|
0.801
|
1.1 📈 Gráficos QQ-Plot de normalidad de la escala de
prosocialidad
# --- 1. Crear el dataframe de diferencias ---
# (Se usa 'datos_completos' del chunk 'recalcular_totales')
datos_diferencias <- datos_completos %>%
mutate(
Dif_Ayudar = Ayudar_B - Ayudar_A,
Dif_Compartir = Compartir_B - Compartir_A,
Dif_Empatia = Empatia_B - Empatia_A,
Dif_Total = Total_B - Total_A
) %>%
select(Dif_Ayudar, Dif_Compartir, Dif_Empatia, Dif_Total)
# --- 2. Pivotar a formato largo para ggplot ---
datos_diferencias_largos <- datos_diferencias %>%
pivot_longer(
cols = everything(),
names_to = "Dimension",
values_to = "Diferencia"
) %>%
# Limpiar nombres para las etiquetas
mutate(Dimension = str_replace(Dimension, "Dif_", "Diferencia en ")) %>%
# Quitar NAs para que el gráfico no de warnings
filter(!is.na(Diferencia))
# --- 3. Crear los 4 gráficos Q-Q Plot ---
ggplot(datos_diferencias_largos, aes(sample = Diferencia)) +
# stat_qq() dibuja los puntos del Q-Q plot
stat_qq() +
# stat_qq_line() dibuja la línea de referencia roja
stat_qq_line(color = "red", linetype = "dashed") +
# Dividir en una cuadrícula de 2x2
facet_wrap(~ Dimension, scales = "free") +
# Títulos (sin emojis)
labs(
title = "Gráficos Q-Q Plot de las Diferencias (Post - Pre)",
subtitle = "Los puntos deben seguir la línea roja para la normalidad",
x = "Cuantiles Teóricos (Normal)",
y = "Cuantiles de la Muestra"
) +
theme_minimal()

2. ⚖️ Análisis Inferencial (Prueba de Wilcoxon)
# (Asegúrate de que 'rstatix', 'dplyr' y 'tidyr' estén en 'setup_librerias')
# --- 1. Crear el dataframe de diferencias ---
datos_diferencias <- datos_completos %>%
mutate(
Ayudar = Ayudar_B - Ayudar_A,
Compartir = Compartir_B - Compartir_A,
Empatia = Empatia_B - Empatia_A,
Total = Total_B - Total_A
) %>%
select(Ayudar, Compartir, Empatia, Total)
# --- 2. Pivotar a formato largo ---
datos_diferencias_largo <- datos_diferencias %>%
pivot_longer(
cols = everything(),
names_to = "Dimension",
values_to = "Diferencia"
) %>%
# Importante: quitar los NAs
filter(!is.na(Diferencia))
# --- 3. Calcular Pruebas de Wilcoxon (Método de 1-muestra sobre la diferencia) ---
wilcox_resultados <- datos_diferencias_largo %>%
group_by(Dimension) %>%
rstatix::wilcox_test(Diferencia ~ 1, mu = 0, detailed = TRUE) %>%
select(Dimension, statistic, p)
# --- 4. Calcular Tamaño del Efecto (r) ---
effect_size_resultados <- datos_diferencias_largo %>%
group_by(Dimension) %>%
rstatix::wilcox_effsize(Diferencia ~ 1, mu = 0) %>%
select(Dimension, effsize, magnitude)
# --- 5. Unir y traducir tablas ---
tabla_inferencia_final <- left_join(wilcox_resultados, effect_size_resultados, by = "Dimension") %>%
select(Dimension, statistic, p, effsize, magnitude) %>%
arrange(factor(Dimension, levels = c("Ayudar", "Compartir", "Empatia", "Total"))) %>%
# --- TRADUCCIÓN DE MAGNITUD (¡CORREGIDA!) ---
mutate(magnitude = case_when(
magnitude == "small" ~ "Pequeño",
magnitude == "moderate" ~ "Mediano",
magnitude == "large" ~ "Grande",
TRUE ~ magnitude #
))
Resultados de las Pruebas de Hipótesis (Wilcoxon Pre vs. Post)
|
Dimensión
|
Estadístico (W)
|
p-value
|
Efecto (r)
|
Magnitud
|
|
Ayudar
|
576
|
0.000
|
0.602
|
Grande
|
|
Compartir
|
86
|
0.345
|
0.098
|
Pequeño
|
|
Empatia
|
460
|
0.005
|
0.428
|
Mediano
|
|
Total
|
740
|
0.000
|
0.624
|
Grande
|
Interpretación: Un p-value menor a
0.05 indica que el cambio entre el Pre-test y el
Post-test es estadísticamente significativo.
📊 Visualización de Resultados (Gráficos Boxplot)
# (Versión Corregida: se añade factor() y se cambia el nombre del dataframe)
# --- 1.A. Crear datos largos (NUEVO NOMBRE) ---
datos_largos_LIMPIO <- datos_completos %>%
select(
Sujeto,
Ayudar_A, Ayudar_B,
Compartir_A, Compartir_B,
Empatia_A, Empatia_B,
Total_A, Total_B
) %>%
pivot_longer(
cols = -Sujeto,
names_to = c("Dimension", "Momento"),
names_pattern = "(.*)_(.)",
values_to = "Puntaje"
) %>%
# --- 1.B. Limpiar y ORDENAR etiquetas ---
mutate(
Momento = recode(Momento, "A" = "Pre-test", "B" = "Post-test"),
# --- ¡LÍNEA AÑADIDA! ---
# Forzamos el orden correcto del eje X
Momento = factor(Momento, levels = c("Pre-test", "Post-test")),
Dimension = factor(Dimension, levels = c("Ayudar", "Compartir", "Empatia", "Total"))
)
# --- 3. Crear los 4 gráficos (VERSIÓN LIMPIA) ---
# (Usando el nuevo dataframe 'datos_largos_LIMPIO')
ggplot(datos_largos_LIMPIO, aes(x = Momento, y = Puntaje, fill = Momento)) +
# --- ÚNICAMENTE EL BOXPLOT ---
geom_boxplot(alpha = 0.7) +
# 4. Facet (divide en 4 gráficos)
facet_wrap(~ Dimension, scales = "free_y") +
# 5. Títulos y Estilos
labs(
title = "Comparación de Puntajes Pre-test vs. Post-test",
subtitle = "Después de la intervención (voluntariado)",
x = "Momento de Medición",
y = "Puntaje Obtenido"
) +
theme_minimal() +
theme(
legend.position = "none", # Quitar la leyenda (es redundante)
strip.text = element_text(size = 12, face = "bold") # Títulos de facetas
)

3. 📊 Estadística Descriptiva Comparativa (Pre vs. Post)
# 1. Calcular descriptivos del PRE-TEST (A)
# (Usará los datos recalculados de 'datos_completos')
desc_pre <- datos_completos %>%
rstatix::get_summary_stats(
Ayudar_A, Compartir_A, Empatia_A, Total_A,
type = "full"
) %>%
select(variable, n, mean, sd, median, min, max) %>%
mutate(Dimension = str_remove(variable, "_A")) %>%
rename(
N_A = n, Media_A = mean, DE_A = sd,
Mediana_A = median, Min_A = min, Max_A = max
) %>%
select(-variable)
# 2. Calcular descriptivos del POST-TEST (B)
desc_post <- datos_completos %>%
rstatix::get_summary_stats(
Ayudar_B, Compartir_B, Empatia_B, Total_B,
type = "full"
) %>%
select(variable, n, mean, sd, median, min, max) %>%
mutate(Dimension = str_remove(variable, "_B")) %>%
rename(
N_B = n, Media_B = mean, DE_B = sd,
Mediana_B = median, Min_B = min, Max_B = max
) %>%
select(-variable)
# 3. Unir las tablas Pre y Post por la 'Dimension'
tabla_descriptivos_comparativos <- left_join(desc_pre, desc_post, by = "Dimension") %>%
arrange(factor(Dimension, levels = c("Ayudar", "Compartir", "Empatia", "Total")))
# 4. Dividir en dos tablas
tabla_desc_comp_1 <- tabla_descriptivos_comparativos %>%
select(Dimension, N_A, N_B, Media_A, Media_B, DE_A, DE_B)
tabla_desc_comp_2 <- tabla_descriptivos_comparativos %>%
select(Dimension, Mediana_A, Mediana_B, Min_A, Min_B, Max_A, Max_B)
Estadística Descriptiva (Pre vs. Post): Tendencia Central
|
Dimensión
|
N (Pre)
|
N (Post)
|
Media (Pre)
|
Media (Post)
|
DE (Pre)
|
DE (Post)
|
|
Ayudar
|
42
|
42
|
21.93
|
23.29
|
3.54
|
2.61
|
|
Compartir
|
42
|
42
|
12.52
|
12.64
|
1.63
|
1.32
|
|
Empatia
|
42
|
42
|
20.02
|
20.74
|
2.78
|
2.39
|
|
Total
|
42
|
42
|
53.59
|
56.02
|
7.32
|
5.43
|
Estadística Descriptiva (Pre vs. Post): Distribución
|
Dimensión
|
Mediana (Pre)
|
Mediana (Post)
|
Mín (Pre)
|
Mín (Post)
|
Máx (Pre)
|
Máx (Post)
|
|
Ayudar
|
22
|
23.0
|
15
|
19
|
28
|
28
|
|
Compartir
|
12
|
12.5
|
8
|
10
|
15
|
15
|
|
Empatia
|
20
|
21.0
|
15
|
16
|
24
|
25
|
|
Total
|
53
|
56.0
|
37
|
45
|
67
|
66
|
4.📍 Identificación de Casos Atípicos
# (Versión "A prueba de fantasmas" - Nombres de variables cambiados)
# (Asegúrate de que 'ggrepel', 'ggplot2', 'dplyr' y 'tidyr' estén en 'setup_librerias')
# --- 1. Preparar los datos largos (NUEVO NOMBRE) ---
datos_largos_FINAL <- datos_completos %>%
select(
Sujeto,
Ayudar_A, Ayudar_B,
Compartir_A, Compartir_B,
Empatia_A, Empatia_B,
Total_A, Total_B
) %>%
pivot_longer(
cols = -Sujeto,
names_to = c("Dimension", "Momento"),
names_pattern = "(.*)_(.)",
values_to = "Puntaje"
) %>%
# --- 1.B. Limpiar y ORDENAR etiquetas ---
mutate(
Momento = recode(Momento, "A" = "Pre-test", "B" = "Post-test"),
# Forzamos el orden correcto del eje X
Momento = factor(Momento, levels = c("Pre-test", "Post-test")),
Dimension = factor(Dimension, levels = c("Ayudar", "Compartir", "Empatia", "Total"))
)
# --- 2. Definir entrevistados y marcar los datos (NUEVO NOMBRE) ---
sujetos_entrevistados <- c("5", "36", "6", "40", "20", "8")
datos_hibrido_FINAL <- datos_largos_FINAL %>%
mutate(
Entrevistado = ifelse(Sujeto %in% sujetos_entrevistados, "Sí", "No")
)
# --- 3. Filtrar solo los datos de los entrevistados (NUEVO NOMBRE) ---
datos_resaltados_FINAL <- datos_hibrido_FINAL %>%
filter(Entrevistado == "Sí")
# --- 4. Crear el gráfico (usando los dataframes NUEVOS) ---
ggplot(datos_hibrido_FINAL, aes(x = Momento, y = Puntaje)) +
geom_boxplot(fill = "grey90", alpha = 0.5, outlier.shape = NA) +
geom_jitter(
aes(color = Entrevistado),
width = 0.25,
alpha = 0.5,
size = 1.5
) +
scale_color_manual(values = c("Sí" = "#E74C3C", "No" = "#7F8C8D")) +
geom_line(
data = datos_resaltados_FINAL, # <-- Usando nombre nuevo
aes(group = Sujeto),
color = "#E74C3C",
linewidth = 0.6,
alpha = 0.8
) +
geom_text_repel(
data = datos_resaltados_FINAL, # <-- Usando nombre nuevo
aes(label = Sujeto),
color = "black",
size = 3,
max.overlaps = 15
) +
facet_wrap(~ Dimension, scales = "free_y") +
labs(
title = "Comparación Pre vs. Post (Estilo Jitter)",
subtitle = "Todos los sujetos mostrados como puntos. Entrevistados (ID) en rojo.",
x = "Momento de Medición",
y = "Puntaje Obtenido"
) +
theme_minimal() +
theme(
legend.position = "none",
strip.text = element_text(size = 12, face = "bold")
)
