1 Introducción

1.1 Objetivo

Elaborar un Análisis Factorial Exploratorio y Confirmatorio para evaluar la calidad de respuestas de herramientas de inteligencia artificial generativa

1.2 Antecedentes

  • Se tienen datos recopilados que evalúan la calidad de respuestas de cinco herramientas de inteligencia artificial generativa tipo texto. Los datos se encuentran en el siguiente enlace:

https://raw.githubusercontent.com/rpizarrog/innovacion-empresarial/refs/heads/main/datos/autoevaluacion%20100%20prompts%2031072025.csv

  • Las herramientas evaluadas citadas en orden alfabético tales como; ChatGPT ver. 4.0 plan limitado desarrollado por Open AI; Bing ahora Copilot de Microsoft Corporation, Redmond, Washington, USA; DeepSeek DeepSeek.com de China; Gemini 2.5. Flash antes Bard de Google LLC, Mountain View, California, USA y Grok 3.0 Fast (xAI).

  • Se elaboró una rúbrica inicial 12 con criterios medibles en una escala de Likert de 5 niveles: 5. Excelente, 4. Muy bueno, 3. Aceptable, 2. Regular, 1. Deficiente.

  • Los criterios que contiene inicialmente la rúbrica son:

    • “Procedimientos técnicos”
    • “Análisis”
    • “Actualidad”
    • “Ejemplos vigentes”
    • “Herramientas actuales”
    • “Aplicación interdisciplinaria”
    • “Secuencia”
    • “Relevancia”
    • “Terminología adecuada”
    • “Precisión”
    • “Ejemplos relevantes”
    • “Ejemplos ilustrativos”
  • Se construyó una batería de 500 prompts con temas relacionados de estadística descriptiva, probabilidad y aplicaciones de estadística y probabilidad.

1.3 Fundamento teórico

1.3.1 Herramientas de inteligencia artifical generativa tipo texto (IAG)

1.3.2 Análisis Factorial Exploratorio (AFE)

1.3.3 Análisis Factorial Confirmatorio

Un Análisis Factorial Confirmatorio (AFC) ayuda a los investigadores a examinar el constructo o los aspectos que definen el aspecto teórico de un concepto y que contiene las variables o criterios de medición en un instrumento de prueba que tal vez pudiera ser un cuestionario, rúbrica, evaluación, entre otros. (Brown 2015)

En este contexto, la AFC se utiliza para verificar el número de dimensiones o factores que existen y la relación entre los criterios de cada factor. Es decir, estadísticamente verifica los criterios que pertenecen a cada factor y diferentes de otro factor y con ello asegura y sugiere la validez o no validez de un instrumento.(Brown 2015)

1.4 Preguntas de investigación y declaración de hipótesis

Las preguntas de investigación y las hipótesis para contrastar son las siguientes:

  • ¿Existen diferencias estadísticamente significativas entre los factores que miden la calidad de respuestas a prompts en las herramientas de IAG?

    • Hipótesis: Entre los factores que miden la calidad de respuestas a prompts en las herramientas de IAG,
      • \(Ho:\) \(\text {No existen diferencias significativas}\)

      • \(Ha:\) \(\text {Si existen diferencias significativas}\)

  • ¿Existe diferencias estadísticamente significativas entre las herramientas evaluadas?

    • Hipótesis: Entre las herramientas evaluadas,
      • \(Ho:\) \(\text {No existen diferencias significativas}\)

      • \(Ha:\) \(\text {Si existen diferencias significativas}\)

2 Desarrollo

2.1 Metodología

  • Se calcula en coeficiente de Cronbach. para garantizar confiabilidad de la rúbrica.

  • Se aplica e interpreta un Análisis Factorial Exploratorio (AFE) con los datos recopilados para garantizar validez del instrumemto y de la rúbrica.

  • Se hace un Análisis Factorial Confirmatorio para consolidar la rúbrica.

  • Se interpretan resultados de manera descriptiva.

  • Se da respuesta a las preguntas de investigación y al contraste de hipótesis.

2.2 Cargar librerías

library(psych)
library(GPArotation)
library(nFactors)
library(readr)
library(tidyverse)
library(stringr)
library(tictoc)
library(ggplot2)
library(lavaan)

2.3 Cargar funciones

# Función para modificar nombres de columnas que pertenecen al constructo
f_modificar_columnas <- function(datos, columnas) {
  datos_modificados <- datos

  colnames(datos_modificados) <- (columnas)
  
  datos_modificados$tipo_prompt <- factor(datos$tipo_prompt)
  datos_modificados$herramienta <- factor(datos$herramienta)
  datos_modificados$no_prompt <- factor(datos$no_prompt)
  return (datos_modificados)
}


# Función para filtrar datos y dejar AFE y AFC
# 70% datos_AFE datos para anális exploratorio
# 30% datos_AFC datos pra análisis confirmatorio
f_datos_AFE_AFC <- function(datos) {
  set.seed(123)  # Semilla para reproducibilidad
  
  columnas <- colnames(datos[,c(2, 4:15)])

  datos_filtrados <- datos %>%
  filter(herramienta %in% c("ChatGpt100", "DeepSeek100", "Grok100", "Gemini100", "Copilot100")) %>% 
  select(all_of(columnas))
  
  n <- nrow(datos_filtrados)
  indices_afe <- sample(seq_len(n), size = round(0.7 * n))
  
  datos_AFE <- datos_filtrados[indices_afe, ]
  datos_AFE <- datos_AFE %>% 
    mutate(herramienta = droplevels(herramienta))


  datos_AFC <- datos_filtrados[-indices_afe, ]
  datos_AFC <- datos_AFC %>% 
    mutate(herramienta = droplevels(herramienta))


  return(list(afe = datos_AFE, afc = datos_AFC))
}


# Función para garantizar varianza diferente cero y Quitar NA
f_limpiar_datos <- function(datos) {
  
  datos_limpios <- na.omit(datos)
  sds <- apply(datos, 2, sd, na.rm = TRUE)
  columnas_problemas <- which(sds == 0)
  columnas_no_problema <- which(sds > 0)
  
  # 5. Filtrar columnas sin problemas
  datos_limpios <- datos_limpios[ , columnas_no_problema]
  
  return (datos_limpios)
}

f_tabla_cargas <- function(cargas, factores) {
  
  # Hacerlo data.frame
  tabla_cargas <- as.data.frame(cargas)
  
  # Poner nombres de columnas y una columna de criterio
  if (factores == 4)
    colnames(tabla_cargas) <- c("F1", "F2", "F3", "F4") # Depende 3 o 4
  if (factores == 3)
    colnames(tabla_cargas) <- c("F1", "F2", "F3") # Depende 3 o 4
  if (factores == 2)
    colnames(tabla_cargas) <- c("F1", "F2") # Depende 2 , 3, o 4
  # Convertir la matriz de cargas a data.frame y añadir nombres de ítems
  tabla_cargas <- tabla_cargas %>%
    rownames_to_column(var = "criterio") %>%
    select(criterio, everything())  # Reordenar columnas tabla_cargas
  
  return (tabla_cargas)
}


# Función que determina y sugiere número de factores del AFE
# Se mide el tiempo aproximadamente 40 segundos
f_AFE <- function (datos) {
  # Iniciar cronómetro
  print ("Tiempo aproximado 50 segundos para simular 100 interacciones con datos diferentes para el AFE")
  tic("Tiempo de fa.parallel")

  # Ejecutar función
  resultado <- fa.parallel(datos, fa = "fa", n.iter = 100)

# Detener cronómetro y mostrar tiempo
toc()

# Ver resultado (opcional)
# print(resultado)

  # Extraer los autovalores reales
  autovalores_reales <- resultado$fa.values

  # Extraer los autovalores simulados promedio
  autovalores_simulados <- resultado$fa.sim

  # Crear tabla comparativa
  tabla_autovalores <- data.frame(
    Factor = 1:length(autovalores_reales),
    Autovalor_Real = round(autovalores_reales, 2),
    Autovalor_Simulado = round(autovalores_simulados, 2),
    Significativo = autovalores_reales > autovalores_simulados
  )
  
  return (tabla_autovalores)
}


f_graf_factores_ggplot <- function(tabla_autovalores) {
  ggplot(tabla_autovalores, aes(x = Factor)) +
    
    # Línea y puntos de autovalores reales
    geom_line(aes(y = Autovalor_Real, color = "Real"), linewidth = 0.8) +
    geom_point(aes(y = Autovalor_Real, color = "Real"), size = 2) +
    geom_text(aes(y = Autovalor_Real, label = round(Autovalor_Real, 2)),
              vjust = -0.8, color = "navy", size = 3) +
    
    # Línea y puntos de autovalores simulados
    geom_line(aes(y = Autovalor_Simulado, color = "Simulado"), linewidth = 0.8, linetype = "dashed") +
    geom_point(aes(y = Autovalor_Simulado, color = "Simulado"), size = 2) +
    geom_text(aes(y = Autovalor_Simulado, label = round(Autovalor_Simulado, 2)),
              vjust = 1.5, color = "gray30", size = 3) +

    # Escala de colores discreta para artículo
    scale_color_manual(values = c("Real" = "navy", "Simulado" = "gray30")) +
    
    # Eje X con enteros
    scale_x_continuous(breaks = seq(min(tabla_autovalores$Factor),
                                    max(tabla_autovalores$Factor), by = 1)) +
    
    # Etiquetas
    labs(title = "Análisis Paralelo de Autovalores",
         x = "Número de factor",
         y = "Autovalores",
         color = "Tipo de autovalor") +
    
    # Tema sobrio
    theme_minimal(base_size = 11) +
    theme(
      legend.position = "right",
      panel.grid.minor = element_blank(),
      axis.title = element_text(face = "bold"),
      plot.title = element_text(face = "bold")
    )
}



# Función para construir AFE varimax y oblimin
# Devolver afe y tabla de cargas
f_AFE_afe_varimax_oblimin <- function(datos, factores) {
  # AFE con rotación varimax (ortogonal)
  afe_varimax <- fa(datos, nfactors = factores, rotate = "varimax", fm = "minres")
  tabla_varimax <- afe_varimax$loadings  # 
  
  # AFE con rotación oblimin (oblicua)
  afe_oblimin <- fa(datos, nfactors = factores, rotate = "oblimin", fm = "minres")
  tabla_oblimin <- afe_oblimin$loadings
  
  # Devolver una lista nombrada
  return(list(
    afe_varimax = afe_varimax,
    cargas_varimax = tabla_varimax,
    afe_oblimin = afe_oblimin,
    cargas_oblimin = tabla_oblimin
  ))
}

2.4 Cargar datos

Al momento de cargar datos se modifican los nombres de columnas para dejarlos listos para efectos de programación.

datos_originales <- read_csv("https://raw.githubusercontent.com/rpizarrog/innovacion-empresarial/refs/heads/main/datos/autoevaluacion%20100%20prompts%2031072025.csv")
# datos_limpios <- na.omit(datos_originales)

2.4.1 Preparar datos

Se modifican las columnas del constructo a los datos originales dejándolos en datos preparados y se declaran tipos de datos factor o categóricos a las columnas tipo_prompt, herramienta y no_prompt.

Los cambios a las columnas quedan de la siguiente manera:

Se redefinen los nombres de columnas para efectos de programamción

  • “Procedimientos técnicos” \(\longrightarrow\) proc_tecnicos
  • “Análisis” \(\longrightarrow\) analisis
  • “Actualidad” \(\longrightarrow\) actualidad
  • “Ejemplos vigentes” \(\longrightarrow\) ejem_vigentes
  • “Herramientas actuales” \(\longrightarrow\) herr_actuales
  • “Aplicación interdisciplinaria” \(\longrightarrow\) aplic_inter
  • “Secuencia” \(\longrightarrow\) secuencia
  • “Relevancia” \(\longrightarrow\) relevancia
  • “Terminología adecuada” \(\longrightarrow\) term_adecuada
  • “Precisión” \(\longrightarrow\) precision
  • “Ejemplos relevantes” \(\longrightarrow\) ejem_relevanges
  • “Ejemplos ilustrativos” \(\longrightarrow\) ejem_ilustrativos
columnas <- c("tipo_prompt", "herramienta", "no_prompt", "proc_tecnicos",                 "analisis", "actualidad", "ejem_vigentes", "herr_actuales",                 "aplic_inter", "secuencia", "relevancia", "term_adecuada", 
              "precision", "ejem_relevantes", "ejem_ilustrativos")

datos_preparados <- f_modificar_columnas(datos_originales, columnas)

2.4.2 Explorar datos preparados

str(datos_preparados)
## spc_tbl_ [630 × 15] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ tipo_prompt      : Factor w/ 1 level "No Experto": 1 1 1 1 1 1 1 1 1 1 ...
##  $ herramienta      : Factor w/ 10 levels "ChatGPT","ChatGpt100",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ no_prompt        : Factor w/ 126 levels "Prompt 1","Prompt 10",..: 1 12 20 21 22 23 24 25 26 2 ...
##  $ proc_tecnicos    : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ analisis         : num [1:630] 5 4 4 4 5 4 4 5 4 5 ...
##  $ actualidad       : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ ejem_vigentes    : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ herr_actuales    : num [1:630] 4 3 3 3 4 4 3 4 3 4 ...
##  $ aplic_inter      : num [1:630] 4 3 3 3 4 4 3 4 3 4 ...
##  $ secuencia        : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ relevancia       : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ term_adecuada    : num [1:630] 5 5 5 5 5 5 4 5 4 5 ...
##  $ precision        : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ ejem_relevantes  : num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  $ ejem_ilustrativos: num [1:630] 5 4 5 4 5 5 4 5 4 5 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   tipo_prompt = col_character(),
##   ..   herramienta = col_character(),
##   ..   no_prompt = col_character(),
##   ..   `Procedimientos técnicos` = col_double(),
##   ..   Análisis = col_double(),
##   ..   Actualidad = col_double(),
##   ..   `Ejemplos vigentes` = col_double(),
##   ..   `Herramientas actuales` = col_double(),
##   ..   `Aplicación interdisciplinaria` = col_double(),
##   ..   Secuencia = col_double(),
##   ..   Relevancia = col_double(),
##   ..   `Terminología adecuada` = col_double(),
##   ..   Precisión = col_double(),
##   ..   `Ejemplos relevantes` = col_double(),
##   ..   `Ejemplos ilustrativos` = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
summary(datos_preparados)
##      tipo_prompt       herramienta      no_prompt   proc_tecnicos 
##  No Experto:630   ChatGpt100 :100   Prompt 1 :  5   Min.   :2.00  
##                   Copilot100 :100   Prompt 10:  5   1st Qu.:4.00  
##                   DeepSeek100:100   Prompt 11:  5   Median :5.00  
##                   Gemini100  :100   Prompt 12:  5   Mean   :4.49  
##                   Grok100    :100   Prompt 13:  5   3rd Qu.:5.00  
##                   ChatGPT    : 26   Prompt 14:  5   Max.   :5.00  
##                   (Other)    :104   (Other)  :600                 
##     analisis       actualidad    ejem_vigentes herr_actuales    aplic_inter  
##  Min.   :1.000   Min.   :2.000   Min.   :1.0   Min.   :1.000   Min.   :1.00  
##  1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.0   1st Qu.:3.000   1st Qu.:3.00  
##  Median :4.000   Median :5.000   Median :4.0   Median :3.500   Median :3.00  
##  Mean   :3.968   Mean   :4.535   Mean   :4.1   Mean   :3.541   Mean   :3.44  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.0   3rd Qu.:4.000   3rd Qu.:4.00  
##  Max.   :5.000   Max.   :5.000   Max.   :5.0   Max.   :5.000   Max.   :5.00  
##                                                                              
##    secuencia       relevancia    term_adecuada     precision    
##  Min.   :2.000   Min.   :2.000   Min.   :3.000   Min.   :2.000  
##  1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.000  
##  Median :5.000   Median :5.000   Median :5.000   Median :5.000  
##  Mean   :4.556   Mean   :4.649   Mean   :4.638   Mean   :4.571  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.000  
##  Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##                                                                 
##  ejem_relevantes ejem_ilustrativos
##  Min.   :1.000   Min.   :1.000    
##  1st Qu.:4.000   1st Qu.:4.000    
##  Median :4.000   Median :4.000    
##  Mean   :4.129   Mean   :4.013    
##  3rd Qu.:5.000   3rd Qu.:5.000    
##  Max.   :5.000   Max.   :5.000    
## 

2.5 Datos par AFE y AFC

Se crean dos conjuntos de datos:

  • datos_AFE que son los datos para AFE, el 70% de los datos ya preparados y limpios
  • datos_AFC que serán para el AFC, el 30% de los datos ya preparados y limpios

Para construir el AFE del conjunto de datos se filtran únicamente los registros que tiene que ver con las evaluaciones de las respuestas de los 500 prompts de cada una de cinco herramientas.

Con otros datos se construye un AFC para confirmar precisamente que los factores que se definen son adecuados para definir el constructo.

# Ejecutar y obtener conjuntos separados
conjuntos <- f_datos_AFE_AFC(datos_preparados)
datos_AFE <- conjuntos$afe
datos_AFC <- conjuntos$afc

2.5.1 Datos para AFE

350 registros, el 70% de los datos originales

# Estructura de los datos
str(datos_AFE)
## tibble [350 × 13] (S3: tbl_df/tbl/data.frame)
##  $ herramienta      : Factor w/ 5 levels "ChatGpt100","Copilot100",..: 1 1 4 5 4 1 3 4 2 2 ...
##  $ proc_tecnicos    : num [1:350] 5 4 4 5 4 5 2 4 4 5 ...
##  $ analisis         : num [1:350] 4 3 4 4 4 4 2 4 5 5 ...
##  $ actualidad       : num [1:350] 5 4 4 5 4 5 3 3 5 5 ...
##  $ ejem_vigentes    : num [1:350] 4 3 4 4 4 4 2 3 4 4 ...
##  $ herr_actuales    : num [1:350] 5 3 3 3 4 5 1 3 4 5 ...
##  $ aplic_inter      : num [1:350] 3 2 4 4 4 3 1 3 5 4 ...
##  $ secuencia        : num [1:350] 5 4 4 5 4 5 3 4 4 5 ...
##  $ relevancia       : num [1:350] 5 4 4 5 4 5 3 4 5 5 ...
##  $ term_adecuada    : num [1:350] 5 4 4 5 4 5 3 4 4 5 ...
##  $ precision        : num [1:350] 5 4 4 5 4 5 2 4 4 5 ...
##  $ ejem_relevantes  : num [1:350] 4 3 4 4 4 4 2 3 4 4 ...
##  $ ejem_ilustrativos: num [1:350] 4 3 4 4 4 4 1 4 4 4 ...
# Descripción de datos 
summary(datos_AFE)
##       herramienta proc_tecnicos      analisis       actualidad   
##  ChatGpt100 :66   Min.   :2.000   Min.   :1.000   Min.   :2.000  
##  Copilot100 :77   1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.000  
##  DeepSeek100:74   Median :5.000   Median :4.000   Median :5.000  
##  Gemini100  :68   Mean   :4.509   Mean   :3.989   Mean   :4.517  
##  Grok100    :65   3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.000  
##                   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##  ejem_vigentes   herr_actuales    aplic_inter      secuencia    
##  Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :2.000  
##  1st Qu.:4.000   1st Qu.:3.000   1st Qu.:3.000   1st Qu.:4.000  
##  Median :4.000   Median :4.000   Median :3.000   Median :5.000  
##  Mean   :3.994   Mean   :3.594   Mean   :3.474   Mean   :4.514  
##  3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:4.000   3rd Qu.:5.000  
##  Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##    relevancia    term_adecuada     precision     ejem_relevantes
##  Min.   :2.000   Min.   :3.000   Min.   :2.000   Min.   :1.00   
##  1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.00   
##  Median :5.000   Median :5.000   Median :5.000   Median :4.00   
##  Mean   :4.594   Mean   :4.569   Mean   :4.531   Mean   :4.02   
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.00   
##  Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.00   
##  ejem_ilustrativos
##  Min.   :1.000    
##  1st Qu.:4.000    
##  Median :4.000    
##  Mean   :3.934    
##  3rd Qu.:4.000    
##  Max.   :5.000

2.5.2 Datos para AFC

150 registros, el 30% de los datos originales

str(datos_AFC)
## tibble [150 × 13] (S3: tbl_df/tbl/data.frame)
##  $ herramienta      : Factor w/ 5 levels "ChatGpt100","Copilot100",..: 5 5 5 5 5 5 5 5 5 5 ...
##  $ proc_tecnicos    : num [1:150] 4 4 5 5 5 4 5 4 5 5 ...
##  $ analisis         : num [1:150] 3 3 4 3 4 5 3 4 4 4 ...
##  $ actualidad       : num [1:150] 5 5 5 5 5 5 5 5 5 5 ...
##  $ ejem_vigentes    : num [1:150] 4 4 4 3 5 4 5 4 5 4 ...
##  $ herr_actuales    : num [1:150] 2 2 2 2 3 3 2 3 3 3 ...
##  $ aplic_inter      : num [1:150] 4 3 3 2 4 4 4 4 4 4 ...
##  $ secuencia        : num [1:150] 5 4 5 4 5 5 4 5 5 5 ...
##  $ relevancia       : num [1:150] 4 4 5 5 5 5 5 5 5 5 ...
##  $ term_adecuada    : num [1:150] 5 5 5 5 5 5 5 5 5 5 ...
##  $ precision        : num [1:150] 4 4 5 5 5 5 5 5 5 5 ...
##  $ ejem_relevantes  : num [1:150] 4 4 4 3 5 4 5 4 5 4 ...
##  $ ejem_ilustrativos: num [1:150] 3 3 4 3 4 4 4 4 4 4 ...
# Descripción de datos 
summary(datos_AFC)
##       herramienta proc_tecnicos      analisis       actualidad   
##  ChatGpt100 :34   Min.   :3.000   Min.   :2.000   Min.   :2.000  
##  Copilot100 :23   1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.000  
##  DeepSeek100:26   Median :5.000   Median :4.000   Median :5.000  
##  Gemini100  :32   Mean   :4.527   Mean   :4.013   Mean   :4.567  
##  Grok100    :35   3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:5.000  
##                   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##  ejem_vigentes   herr_actuales    aplic_inter      secuencia    
##  Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :3.000  
##  1st Qu.:4.000   1st Qu.:3.000   1st Qu.:3.000   1st Qu.:4.000  
##  Median :4.000   Median :3.500   Median :4.000   Median :5.000  
##  Mean   :4.047   Mean   :3.567   Mean   :3.547   Mean   :4.533  
##  3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:4.000   3rd Qu.:5.000  
##  Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##    relevancia    term_adecuada     precision    ejem_relevantes
##  Min.   :3.000   Min.   :3.000   Min.   :3.00   Min.   :2.000  
##  1st Qu.:4.000   1st Qu.:4.000   1st Qu.:4.00   1st Qu.:4.000  
##  Median :5.000   Median :5.000   Median :5.00   Median :4.000  
##  Mean   :4.627   Mean   :4.613   Mean   :4.56   Mean   :4.087  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.00   3rd Qu.:5.000  
##  Max.   :5.000   Max.   :5.000   Max.   :5.00   Max.   :5.000  
##  ejem_ilustrativos
##  Min.   :1.000    
##  1st Qu.:4.000    
##  Median :4.000    
##  Mean   :3.907    
##  3rd Qu.:4.000    
##  Max.   :5.000

3 Resultados

3.1 Factores sugeridos para AFE

Con los datos preparados de las evaluaciones de las respuestas de las herramientas IAG identificados en un data.frame como datos_AFE, se determina la cantidad de factores sugeridos con funciones de la librería nFactors con tabla tabla y visualmente incluyendo también con funciones de librería ggplot2.

La función fa.parallel() que de manera interna se ejecuta en las funcione personalizadas que ejecutan fa para AFE del paquete psych en R se utiliza para realizar un análisis paralelo (parallel analysis). Esta es una técnica estadística recomendable para determinar cuántos factores o componentes se deben retener en un análisis factorial exploratorio (AFE) o un análisis de componentes principales (ACP). Aqauí se utilizón para AFE.

Solo se analizan los datos numéricos datos_AFE[,2:13], es decir los valores de los criterios.

tabla_autovalores <- f_AFE(datos_AFE[,2:13])
## [1] "Tiempo aproximado 50 segundos para simular 100 interacciones con datos diferentes para el AFE"

## Parallel analysis suggests that the number of factors =  3  and the number of components =  NA 
## Tiempo de fa.parallel: 41.295 sec elapsed
print (tabla_autovalores)
##    Factor Autovalor_Real Autovalor_Simulado Significativo
## 1       1           7.40               0.51          TRUE
## 2       2           1.23               0.24          TRUE
## 3       3           0.32               0.19          TRUE
## 4       4           0.11               0.13         FALSE
## 5       5          -0.05               0.09         FALSE
## 6       6          -0.15               0.04         FALSE
## 7       7          -0.16               0.00         FALSE
## 8       8          -0.18              -0.04         FALSE
## 9       9          -0.22              -0.09         FALSE
## 10     10          -0.25              -0.13         FALSE
## 11     11          -0.27              -0.18         FALSE
## 12     12          -0.38              -0.24         FALSE

Usando funciones de ggplot2 se observa que se recomiendan 3 factores, sin embargo, 2 de ellos son claramente distinguibles.

De acuerdo a Chat GPT, la gráfica de análisis paralelo muestra la comparación entre los autovalores reales (en azul) y los autovalores simulados (en gris).

Este procedimiento permite determinar cuántos factores deben retenerse en un análisis factorial exploratorio, bajo el criterio de que solo deben conservarse aquellos factores cuyo autovalor real supere claramente al correspondiente valor simulado, ya que esto sugiere que aportan varianza sistemática y no aleatoria.

En este caso: Los tres primeros factores tienen autovalores reales por encima de los simulados, lo que sugiere la retención de tres factores.

Sin embargo, se observa que:

El primer factor tiene un autovalor significativamente más alto \(7.40\) valor real sobre aproximadamente \(0.50\) del valor simulado, lo que indica que concentra la mayor parte de la varianza explicada.

El segundo factor tiene valores de \(1.23\) también se sitúa de forma clara sobre el valor simulado aproximado de \(0.25\), aunque con menor diferencia.

El tercer factor \(0.32\) apenas supera al autovalor simulado aproximado de \(0.19\), lo que indica una contribución marginal y cuestionable desde el punto de vista de su solidez estructural.

Los resultados de la tabla arrojan que hay 2 factores que superan claramente y están por encima de los factores simulados.

Existe un tercer factor que servirá para siguientes pruebas de AFE y AFC.

Existe aunque no estadísticamente tal vez un cuarto pero eso queda a decisión del investigador tratar con 4 factores sugeridos que puede acarrear situaciones de factores muy correlacionados.

Por otra parte la gráfica de factores indica con la linea azul que hay tres puntos que representan los factores están por encima de los factores de la linea gris que son los datos simulados.

Ambas gráficas se interpretan que se sugieren 3 factores para el instrumento o rúbrica aplicada, aunque con mayor claridad 2 factores.

f_graf_factores_ggplot(tabla_autovalores)

3.2 AFE

Con estos mismos datos datos_AFE, Se construye un AFE con 3 factores que fueron previamente sugeridos y se hace la prueba con 2 factores para posibles depuraciones.

3.2.1 AFE Para tres factores

3.2.1.1 Rotación varimax tres factores

n_factores <- 3
resultado <- f_AFE_afe_varimax_oblimin(datos_AFE[,2:13], factores = n_factores)

resultado$cargas_varimax
## 
## Loadings:
##                   MR1   MR2   MR3  
## proc_tecnicos     0.889 0.195 0.192
## analisis          0.123 0.398 0.907
## actualidad        0.662 0.548 0.111
## ejem_vigentes     0.347 0.878 0.244
## herr_actuales     0.331 0.123 0.435
## aplic_inter       0.155 0.558 0.378
## secuencia         0.869 0.264 0.263
## relevancia        0.680 0.554 0.211
## term_adecuada     0.862 0.267 0.165
## precision         0.919 0.267 0.197
## ejem_relevantes   0.348 0.882 0.274
## ejem_ilustrativos 0.299 0.639 0.578
## 
##                  MR1   MR2   MR3
## SS loadings    4.514 3.301 1.854
## Proportion Var 0.376 0.275 0.154
## Cumulative Var 0.376 0.651 0.806
# resultado$modelo_varimax
fa.diagram(resultado$afe_varimax, main = "Análisis Factorial Exploratorio (AFE) con 3 factores y rotación 'varimax'")

La tabla arroja que todas las cargas superan el valor de 0.40 que de acuerdo a son cargas adecuadas para clarificar criterios. Cita Bibliográfica; además, la varianza acumulada es aproximadamente de 0.80 lo que significa que el constructo es representado en un 80% por 3 factores.

De acuerdo a una rotación varimax en el AFE de 3 factores se sugieren: 6 criterios para F1, 3 para el F2 y 3 para el F3.

  • F1 \(\longrightarrow\) \(\text {precision + proc_tecnicos + secuencia + term_adecuada + relevancia + actualidad }\)
  • F2 \(\longrightarrow\) \(\text {ejem_relevantes + ejem_vigentes + ejem_ilustrativos + aplic_inter }\)
  • F3 \(\longrightarrow\) \(\text {analisis + herr_actuales}\)

3.2.1.2 Rotación oblimin tres factores

resultado$cargas_oblimin
## 
## Loadings:
##                   MR1    MR2    MR3   
## proc_tecnicos      0.968              
## analisis                         0.966
## actualidad         0.531  0.493 -0.114
## ejem_vigentes             0.948       
## herr_actuales      0.360 -0.141  0.427
## aplic_inter               0.510  0.296
## secuencia          0.916              
## relevancia         0.555  0.448       
## term_adecuada      0.901              
## precision          0.970              
## ejem_relevantes           0.938       
## ejem_ilustrativos         0.480  0.488
## 
##                  MR1   MR2   MR3
## SS loadings    4.261 2.744 1.468
## Proportion Var 0.355 0.229 0.122
## Cumulative Var 0.355 0.584 0.706
fa.diagram(resultado$afe_oblimin, main = "Análisis Factorial Exploratorio (AFE) con 3 factores y rotación 'oblimin'")

La tabla arroja que todas las cargas superan el valor de 0.40 que de acuerdo a son cargas adecuadas para clarificar criterios. Cita Bibliográfica; además, la varianza acumulada es aproximadamente de 0.70 lo que significa que el constructo es representado en un 70% por 3 factores en rotación oblimin.

Por otra parte, de acuerdo a una rotación oblimin en el AFE de 3 factores organizados en estos criterios: 6 criterios para F1, 3 para el F2 y 3 para el F3

  • F1 \(\longrightarrow\) \(\text {precision + proc_tecnicos + secuencia + term_adecuada + relevancia + actualidad }\)
  • F2 \(\longrightarrow\) \(\text {ejem_vigentes + ejem_relevantes + aplic_inter }\)
  • F3 \(\longrightarrow\) \(\text {analisis + ejem_ilustrativos + herr_actuales}\)

Se observa que hay 3 factores y que el primer y segundo factor se correlacionan en un 60%; el segundo y tercer factor se correlacionan en un 60% también; el primer y tercer factor se correlacionan en un 40%.

3.2.2 AFE Para dos factores

Se realiza el AFE a 2 factores de igual forma con rotación varimax y oblimin.

3.2.2.1 Rotación varimax dos factores

n_factores <- 2
resultado <- f_AFE_afe_varimax_oblimin(datos_AFE[,2:13], factores = n_factores)

resultado$cargas_varimax
## 
## Loadings:
##                   MR1   MR2  
## proc_tecnicos     0.897 0.226
## analisis          0.189 0.751
## actualidad        0.690 0.478
## ejem_vigentes     0.406 0.822
## herr_actuales     0.331 0.336
## aplic_inter       0.181 0.684
## secuencia         0.881 0.325
## relevancia        0.711 0.542
## term_adecuada     0.879 0.267
## precision         0.936 0.284
## ejem_relevantes   0.406 0.847
## ejem_ilustrativos 0.327 0.863
## 
##                  MR1   MR2
## SS loadings    4.828 4.113
## Proportion Var 0.402 0.343
## Cumulative Var 0.402 0.745
# resultado$modelo_varimax
fa.diagram(resultado$afe_varimax, main = "Análisis Factorial Exploratorio (AFE) con 2 factores y rotación 'varimax'")

Todas las cargas superan el valor de 0.40 que de acuerdo a son cargas adecuadas para clarificar criterios. Cita Bibliográfica. excepto herr_actuales 0.331 0.336.

La varianza acumulada es aproximadamente de 0.74 lo que significa que el constructo es representado en un 74% por 2 factores en rotación varimax.

3.2.2.2 Rotación oblimin dos factores

resultado$cargas_oblimin
## 
## Loadings:
##                   MR1    MR2   
## proc_tecnicos      0.972       
## analisis          -0.114  0.840
## actualidad         0.610  0.311
## ejem_vigentes      0.114  0.842
## herr_actuales      0.244  0.279
## aplic_inter               0.761
## secuencia          0.908       
## relevancia         0.606  0.381
## term_adecuada      0.932       
## precision          0.992       
## ejem_relevantes    0.102  0.872
## ejem_ilustrativos         0.923
## 
##                  MR1   MR2
## SS loadings    4.468 3.936
## Proportion Var 0.372 0.328
## Cumulative Var 0.372 0.700
# resultado$modelo_oblimin
fa.diagram(resultado$afe_oblimin, main = "Análisis Factorial Exploratorio (AFE) con 2 factores y rotación 'oblimin'")

Con rotación oblimin a 2 factores, todas las cargas superan el 0.40 excepto el criterio de herr_actuales con valores de 0.244 0.279 en ambos factores, lo que sugiere posiblemente eliminar dicho criterio dado que no representa significado para el constructo para cualquiera de los dos factores.

Los facTores se correlaciones en un 60%, se sugieren 6 criterios para el F1 y 5 criterios para el F2 de acuerdo a la rotación oblimin:

  • F1 \(\longrightarrow\) \(\text {precision + proc_tecnicos + term_adecuada + secuencia + actualidad + relevancia}\)

  • F2 \(\longrightarrow\) \(\text {ejem_ilustrativos + ejem_relevantes + ejem_vigentes + analisis + aplic_inter}\)

Se recomienda eliminar el criterio herr_actuales

3.3 AFC

Con los datos identificados en el data.frame como datos_AFC y que son diferentes a los que se usaron para construir el AFE y con la librería lavaan se hace el análisis factorial exploratorio.

Igual pueden ser otros datos recabados con los mismos criterios.

3.3.1 Modelo AFC con 3 factores

F1 =~ precision + proc_tecnicos + secuencia + term_adecuada + relevancia + actualidad

F2 =~ ejem_vigentes + ejem_relevantes + aplic_inter

F3 =~ analisis + ejem_ilustrativos + herr_actuales

# Especificas el modelo con base en AFE
modelo_cfa <- '
F1 =~ precision + proc_tecnicos + secuencia + term_adecuada + relevancia + actualidad
F2 =~ ejem_vigentes + ejem_relevantes + aplic_inter
F3 =~ analisis + ejem_ilustrativos + herr_actuales
'

# Ajustas el modelo con el conjunto de validación
fit_cfa <- cfa(modelo_cfa, data = datos_AFC, std.lv = TRUE)
summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)
## lavaan 0.6-19 ended normally after 73 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        27
## 
##   Number of observations                           150
## 
## Model Test User Model:
##                                                       
##   Test statistic                               325.506
##   Degrees of freedom                                51
##   P-value (Chi-square)                           0.000
## 
## Model Test Baseline Model:
## 
##   Test statistic                              2377.891
##   Degrees of freedom                                66
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.881
##   Tucker-Lewis Index (TLI)                       0.846
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)               -873.033
##   Loglikelihood unrestricted model (H1)       -710.280
##                                                       
##   Akaike (AIC)                                1800.066
##   Bayesian (BIC)                              1881.353
##   Sample-size adjusted Bayesian (SABIC)       1795.903
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.189
##   90 Percent confidence interval - lower         0.170
##   90 Percent confidence interval - upper         0.209
##   P-value H_0: RMSEA <= 0.050                    0.000
##   P-value H_0: RMSEA >= 0.080                    1.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.067
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   F1 =~                                                                 
##     precision         0.586    0.035   16.793    0.000    0.586    0.985
##     proc_tecnicos     0.517    0.037   13.794    0.000    0.517    0.883
##     secuencia         0.567    0.036   15.692    0.000    0.567    0.951
##     term_adecuada     0.520    0.035   14.878    0.000    0.520    0.923
##     relevancia        0.496    0.035   14.375    0.000    0.496    0.905
##     actualidad        0.555    0.048   11.523    0.000    0.555    0.786
##   F2 =~                                                                 
##     ejem_vigentes     0.802    0.048   16.835    0.000    0.802    0.988
##     ejem_relevants    0.760    0.046   16.619    0.000    0.760    0.982
##     aplic_inter       0.462    0.061    7.565    0.000    0.462    0.569
##   F3 =~                                                                 
##     analisis          0.466    0.051    9.091    0.000    0.466    0.673
##     ejem_ilustrtvs    0.831    0.050   16.514    0.000    0.831    1.035
##     herr_actuales     0.352    0.077    4.597    0.000    0.352    0.355
## 
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   F1 ~~                                                                 
##     F2                0.702    0.043   16.396    0.000    0.702    0.702
##     F3                0.645    0.050   12.923    0.000    0.645    0.645
##   F2 ~~                                                                 
##     F3                0.780    0.039   20.099    0.000    0.780    0.780
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .precision         0.010    0.003    3.585    0.000    0.010    0.029
##    .proc_tecnicos     0.076    0.009    8.118    0.000    0.076    0.220
##    .secuencia         0.034    0.005    7.071    0.000    0.034    0.096
##    .term_adecuada     0.047    0.006    7.747    0.000    0.047    0.148
##    .relevancia        0.054    0.007    7.957    0.000    0.054    0.181
##    .actualidad        0.191    0.023    8.419    0.000    0.191    0.382
##    .ejem_vigentes     0.015    0.008    1.880    0.060    0.015    0.023
##    .ejem_relevants    0.022    0.008    2.880    0.004    0.022    0.036
##    .aplic_inter       0.447    0.052    8.602    0.000    0.447    0.677
##    .analisis          0.263    0.032    8.105    0.000    0.263    0.548
##    .ejem_ilustrtvs   -0.046    0.039   -1.190    0.234   -0.046   -0.072
##    .herr_actuales     0.855    0.098    8.718    0.000    0.855    0.874
##     F1                1.000                               1.000    1.000
##     F2                1.000                               1.000    1.000
##     F3                1.000                               1.000    1.000

3.3.2 Modelo AFC con 2 factores

F1 =~ precision + proc_tecnicos + term_adecuada + secuencia + actualidad + relevancia

F2 =~ ejem_ilustrativos + ejem_relevantes + ejem_vigentes + analisis + aplic_inter ’

# Especificas el modelo con base en AFE
modelo_cfa <- '
F1 =~ precision + proc_tecnicos + term_adecuada + secuencia + actualidad + relevancia 
F2 =~ ejem_ilustrativos + ejem_relevantes + ejem_vigentes + analisis + aplic_inter 
'

# Ajustas el modelo con el conjunto de validación
fit_cfa <- cfa(modelo_cfa, data = datos_AFC, std.lv = TRUE)
summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)
## lavaan 0.6-19 ended normally after 60 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        23
## 
##   Number of observations                           150
## 
## Model Test User Model:
##                                                       
##   Test statistic                               318.518
##   Degrees of freedom                                43
##   P-value (Chi-square)                           0.000
## 
## Model Test Baseline Model:
## 
##   Test statistic                              2279.969
##   Degrees of freedom                                55
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.876
##   Tucker-Lewis Index (TLI)                       0.842
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)               -707.259
##   Loglikelihood unrestricted model (H1)       -548.000
##                                                       
##   Akaike (AIC)                                1460.518
##   Bayesian (BIC)                              1529.763
##   Sample-size adjusted Bayesian (SABIC)       1456.972
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.207
##   90 Percent confidence interval - lower         0.186
##   90 Percent confidence interval - upper         0.228
##   P-value H_0: RMSEA <= 0.050                    0.000
##   P-value H_0: RMSEA >= 0.080                    1.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.065
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   F1 =~                                                                 
##     precision         0.585    0.035   16.760    0.000    0.585    0.984
##     proc_tecnicos     0.517    0.037   13.792    0.000    0.517    0.883
##     term_adecuada     0.520    0.035   14.903    0.000    0.520    0.924
##     secuencia         0.566    0.036   15.668    0.000    0.566    0.950
##     actualidad        0.557    0.048   11.586    0.000    0.557    0.789
##     relevancia        0.497    0.034   14.420    0.000    0.497    0.907
##   F2 =~                                                                 
##     ejem_ilustrtvs    0.649    0.054   12.014    0.000    0.649    0.808
##     ejem_relevants    0.762    0.046   16.726    0.000    0.762    0.985
##     ejem_vigentes     0.799    0.048   16.734    0.000    0.799    0.985
##     analisis          0.350    0.053    6.576    0.000    0.350    0.505
##     aplic_inter       0.465    0.061    7.611    0.000    0.465    0.572
## 
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   F1 ~~                                                                 
##     F2                0.707    0.042   16.784    0.000    0.707    0.707
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .precision         0.011    0.003    3.725    0.000    0.011    0.031
##    .proc_tecnicos     0.076    0.009    8.100    0.000    0.076    0.221
##    .term_adecuada     0.046    0.006    7.705    0.000    0.046    0.146
##    .secuencia         0.035    0.005    7.059    0.000    0.035    0.098
##    .actualidad        0.188    0.022    8.406    0.000    0.188    0.377
##    .relevancia        0.054    0.007    7.918    0.000    0.054    0.178
##    .ejem_ilustrtvs    0.224    0.027    8.415    0.000    0.224    0.347
##    .ejem_relevants    0.018    0.007    2.740    0.006    0.018    0.031
##    .ejem_vigentes     0.020    0.007    2.696    0.007    0.020    0.030
##    .analisis          0.358    0.041    8.616    0.000    0.358    0.745
##    .aplic_inter       0.445    0.052    8.598    0.000    0.445    0.673
##     F1                1.000                               1.000    1.000
##     F2                1.000                               1.000    1.000

De acuerdo a la interprtación de ChatGPT:

A partir del análisis factorial confirmatorio (AFC), puede concluirse que la rúbrica utilizada ofrece validez estructural suficiente bajo un modelo de 2 factores, en la medida en que más del 90% de los criterios presentan cargas aceptables o elevadas, y se alcanzan valores adecuados en índices de ajuste como el SRMR y, en menor medida, el CFI.

Si bien el RMSEA excede los umbrales óptimos, lo anterior no invalida el modelo, sino que sugiere la necesidad de mejoras futuras.

En conjunto, estos resultados respaldan la estructura factorial propuesta y permiten considerar que el instrumento posee una validez estructural preliminar satisfactoria para estudios exploratorios o de uso inicial.

3.4 Análisis descriptivo

De los 500 datos preparados se extrae una muestra al 99% de confianza y 5% de margen de error.

$$

n =

$$

f_extraer_muestra <- function(datos_AFE, datos_AFC, nivel_confianza = 0.99, margen_error = 0.05, proporcion = 0.5, semilla = 123) {
  # Combinar los dos conjuntos de datos
  datos_combinados <- rbind(datos_AFE, datos_AFC)
  N <- nrow(datos_combinados)
  
  # Valor Z según el nivel de confianza
  Z <- if (nivel_confianza == 0.99) 2.576 else if (nivel_confianza == 0.95) 1.96 else qnorm(1 - (1 - nivel_confianza)/2)
  
  # Cálculo del tamaño de la muestra para población finita
  n <- round((N * Z^2 * proporcion * (1 - proporcion)) / ((margen_error^2 * (N - 1)) + (Z^2 * proporcion * (1 - proporcion))))
  
  # Extraer muestra aleatoria
  set.seed(semilla)
  muestra <- datos_combinados[sample(1:N, size = n), ]
  
  return(muestra)
}

muestra <- f_extraer_muestra(datos_AFE , datos_AFC)

# Convierte los datos numéricos a un solo vector
valores <- unlist(muestra[, 2:13])

# Media global
media_global <- mean(valores, na.rm = TRUE)

# Desviación estándar global
desv_std_global <- sd(valores, na.rm = TRUE)

# Mostrar resultados

print (paste("Media artimética de todo el constructo: ", round(media_global, 4)))
## [1] "Media artimética de todo el constructo:  4.2237"
print (paste("Desviación estándar de todo el constructo: ", round(desv_std_global, 4)))
## [1] "Desviación estándar de todo el constructo:  0.8241"
library(tidyverse)

# Calcular medias y desviaciones estándar
resumen <- muestra[, 2:13] %>%
  pivot_longer(cols = everything(), names_to = "Criterio", values_to = "Valor") %>%
  group_by(Criterio) %>%
  summarise(
    Media = mean(Valor, na.rm = TRUE),
    Desv = sd(Valor, na.rm = TRUE)
  ) %>%
  mutate(
    Media_lbl = round(Media, 2),
    Desv_lbl = round(Desv, 2)
  )

# Gráfico con estilo científico
ggplot(resumen, aes(x = reorder(Criterio, -Media), y = Media)) +
  geom_col(fill = "gray70", color = "gray30", width = 0.7) +
  geom_errorbar(aes(ymin = Media - Desv, ymax = Media + Desv), width = 0.2, color = "black", linewidth = 0.6) +

  # Etiquetas numéricas
  geom_text(aes(label = Media_lbl, y = Media + 0.05), size = 3.2, vjust = 0, color = "black") +
  geom_text(aes(label = Desv_lbl, y = Media + Desv + 0.05), size = 3.2, vjust = 0, color = "gray30") +

  # Título y ejes
  labs(title = "Media y desviación estándar por criterio",
       x = "Criterio", y = "Media (escala Likert 1–5)") +

  # Tema académico sobrio
  theme_minimal(base_size = 11) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank()
  )

Relevancia, terminología adecuada y precisión son los criterios mejor evaluados, con medias cercanas a 4.61 - 4.55

Aplicación interdisciplinaria y herramientas actuales presentan las medias más bajas de 3.63 y 3.56, lo cual sugiere oportunidades de mejora en esos aspectos.

Las barras de error en color negro muestran la variabilidad de cada criterio. Una desviación más alta (como en herr_actuales) indica opiniones más dispersas entre los evaluadores o las herramientas autoevaluadas.

En general, las medias son altas, lo que sugiere buena percepción global de la rúbrica, aunque algunos criterios específicos tienen menor consenso.

4 Interpretación

5 Conclusiones

Bibliografía

Brown, Timothy A. 2015. Confirmatory Factor Analysis for Applied Research. Second. Series Editor’s Note by Todd D. Little. ThE GUILFORD PRESS.