📚 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 <- readxl::read_excel(path_cuanti)

# --- 2. Limpieza y Renombrado (UN solo transmute, sin anidar) ---
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) ---
    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) ---
    B_item1  = as.numeric(`X47..B_Item1`),
    B_item2  = as.numeric(`X48..B_Item2`),
    B_item3  = as.numeric(`X49..B_Item3`),
    B_item4  = as.numeric(`X50..B_Item4`),
    B_item5  = as.numeric(`X51..B_Item5`),
    B_item6  = as.numeric(`X52..B_Item6`),
    B_item7  = as.numeric(`X53..B_Item7`),
    B_item8  = as.numeric(`X54..B_Item8`),
    B_item9  = as.numeric(`X55..B_Item9`),
    B_item10 = as.numeric(`X56..B_Item10`),
    B_item11 = as.numeric(`X57..B_Item11`),
    B_item12 = as.numeric(`X58..B_Item12`),
    B_item13 = as.numeric(`X59..B_Item13`),
    B_item14 = as.numeric(`X60..B_Item14`),
    B_item15 = as.numeric(`X61..B_Item15`),
    B_item16 = as.numeric(`X62..B_Item16`)
  )

# --- Mensaje de confirmación ---
cat("--- Carga y limpieza Fase 2 COMPLETA ---\n")
## --- Carga y limpieza Fase 2 COMPLETA ---
cat("Filas cargadas:", nrow(datos_completos), "\n")
## Filas cargadas: 39
## --- Recálculo de subescalas y totales COMPLETO ---
## Ayudar, Compartir y Empatía recalculadas (A y B) según definición.
## Totales (A y B)

📊 Fiabilidad de la Escala (Post-test)

# Dimensión 1: Ayudar 
items_ayudar_b <- datos_completos %>%
  select(B_item1, B_item3, B_item4, B_item6, B_item7, B_item13)

# Dimensión 2: Empatía 
items_empatia_b <- datos_completos %>%
  select(B_item5, B_item8, B_item10, B_item12, B_item16)

# Dimensión 3: Compartir 
items_compartir_b <- datos_completos %>%
  select(B_item2, B_item9, B_item14)

# Dimensión 4: Total 
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                       
  )

# --- 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.625
Empatía (Post) 5 0.570
Compartir (Post) 3 0.322
Escala Total (Post) 14 0.788


📈 Gráficos QQ-Plot de normalidad de la escala de prosocialidad

# --- 1. Crear el dataframe de diferencias ---

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))

# --- Etiquetas personalizadas para las facetas ---

 facet_labels <- c(
  "Diferencia en Ayudar"    = "Ayudar",
  "Diferencia en Compartir" = "Compartir",
  "Diferencia en Empatia"   = "Empatía",
  "Diferencia en Total"     = "Total Escala"
)

# --- Gráficos Q-Q Plot con formato uniforme ---
ggplot(datos_diferencias_largos, aes(sample = Diferencia)) +
  
  # Puntos con color vivo y transparencia
  geom_qq(color = "#1ABC9C", size = 2, alpha = 0.8) +
  
  # Línea de referencia en gris oscuro
  geom_qq_line(color = "gray30", linetype = "dashed", linewidth = 1) +
  
  # Facetas con etiquetas personalizadas
  facet_wrap(~ Dimension, scales = "free", labeller = as_labeller(facet_labels)) +
  
  # Títulos y etiquetas
  labs(
    title = "Q-Q Plots de Normalidad (Fase 2 - Diferencias Post - Pre)",
    x = "Cuantiles teóricos",
    y = "Cuantiles observados"
  ) +
  
  # Tema con más contraste
  theme_bw(base_size = 13) +
  theme(
    strip.background = element_rect(fill = "#34495E", color = NA),   # fondo oscuro
    strip.text = element_text(face = "bold", size = 12, color = "white"), # texto blanco
    plot.title = element_text(face = "bold", hjust = 0.5, size = 14)
  )

⚖️ Análisis Inferencial (Prueba de Wilcoxon)

# --- 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"
  ) %>%
  filter(!is.na(Diferencia))

# --- 3. Pruebas de Wilcoxon (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. 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 ---
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"))) %>%
  mutate(
    Dimension = recode(Dimension, "Empatia" = "Empatía"),
    p = ifelse(p < 0.001, "< .001", round(p, 3)),
    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 484.5 < .001 0.603 Grande
Compartir 59.5 0.669 0.018 Pequeño
Empatía 377.5 0.01 0.413 Mediano
Total 622.0 < .001 0.590 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. Además, el tamaño del efecto (r) indica la magnitud práctica del cambio: pequeño, mediano o grande.


📊 Visualización de Resultados (Gráficos Boxplot)

# 1.A. Crear datos largos
datos_largos_para_grafico <- 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. Etiquetas y orden correctos
  mutate(
    Momento = recode(Momento, "A" = "Pre-test", "B" = "Post-test"),
    Momento = factor(Momento, levels = c("Pre-test", "Post-test")),   # orden temporal
    Dimension = factor(Dimension, levels = c("Ayudar", "Compartir", "Empatia", "Total"))
  )

# --- 2. Crear los 4 gráficos (VERSIÓN LIMPIA) ---
ggplot(datos_largos_para_grafico, aes(x = Momento, y = Puntaje, fill = Momento)) +
  geom_boxplot(alpha = 0.7) +
  facet_wrap(~ Dimension, scales = "free_y") +
  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"
  ) +
  scale_fill_manual(values = c("Pre-test" = "#7FB3D5", "Post-test" = "#1F618D")) +  # opcional, colores consistentes
  theme_minimal() +
  theme(
    legend.position = "none",
    strip.text = element_text(size = 12, face = "bold")
  )

📊 Estadística Descriptiva Comparativa (Pre vs. Post)

# 1. Calcular descriptivos del PRE-TEST (A)
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"))) %>%
  mutate(Dimension = recode(Dimension, "Empatia" = "Empatía"))

# 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 39 39 22.05 23.39 3.49 2.61
Compartir 39 39 12.72 12.77 1.47 1.27
Empatía 39 39 20.28 20.95 2.71 2.32
Total 39 39 54.15 56.46 7.23 5.29

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 15 19 28 28
Compartir 13 13 9 10 15 15
Empatía 21 21 15 17 24 25
Total 53 56 37 48 67 66

Interpretación: Estas tablas muestran cómo cambian las medidas de tendencia central y distribución entre el Pre-test y el Post-test. La comparación permite observar tanto el promedio y la dispersión como la forma de la distribución en cada dimensión.


📍 Identificación de Casos Atípicos

# --- 1. Preparar datos largos ---
datos_largos_para_grafico <- 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"
  ) %>%
  mutate(
    Momento = recode(Momento, "A" = "Pre-test", "B" = "Post-test"),
    Momento = factor(Momento, levels = c("Pre-test", "Post-test")),
    Dimension = recode(Dimension, "Empatia" = "Empatía")
  ) %>%
  filter(!is.na(Puntaje))

# --- 2. Sujetos entrevistados ---
sujetos_entrevistados <- c("5", "36", "6", "40", "20", "2")
datos_resaltados <- datos_largos_para_grafico %>%
  filter(Sujeto %in% sujetos_entrevistados)

# --- 3. Gráfico spaghetti con todos en gris y entrevistados en color ---
ggplot(datos_largos_para_grafico, aes(x = Momento, y = Puntaje, group = Sujeto)) +
  # Todos los sujetos en gris tenue
  geom_line(color = "gray80", linewidth = 0.3, alpha = 0.4) +
  
  # Sujetos entrevistados resaltados
  geom_line(data = datos_resaltados, aes(color = Sujeto), linewidth = 0.8) +
  geom_point(data = datos_resaltados, aes(color = Sujeto), size = 2) +
  
  # Etiqueta discreta para el sujeto 20
  ggrepel::geom_text_repel(
    data = datos_resaltados %>% filter(Sujeto == "20"),
    aes(label = Sujeto),
    color = "gray40",
    size = 3   # más pequeño y en gris
  ) +
  
  facet_wrap(~ Dimension, scales = "free_y") +
  labs(
    title = "Trayectorias individuales Pre-test vs. Post-test",
    subtitle = "Sujetos entrevistados resaltados en color; resto en gris tenue",
    x = "Momento de Medición",
    y = "Puntaje Obtenido"
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    strip.text = element_text(size = 12, face = "bold")
  )