Elaborar un Análisis Factorial Exploratorio y Confirmatorio para evaluar la calidad de respuestas de herramientas de inteligencia artificial generativa
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:
Se construyó una batería de 500 prompts con temas relacionados de estadística descriptiva, probabilidad y aplicaciones de estadística y probabilidad.
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)
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?
\(Ho:\) \(\text {No existen diferencias significativas}\)
\(Ha:\) \(\text {Si existen diferencias significativas}\)
¿Existe diferencias estadísticamente significativas entre las herramientas evaluadas?
\(Ho:\) \(\text {No existen diferencias significativas}\)
\(Ha:\) \(\text {Si existen diferencias significativas}\)
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.
library(psych)
library(GPArotation)
library(nFactors)
library(readr)
library(tidyverse)
library(stringr)
library(tictoc)
library(ggplot2)
library(lavaan)
# 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
))
}
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)
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
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)
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
##
Se crean dos conjuntos de datos:
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
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
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
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)
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.
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.
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
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%.
Se realiza el AFE a 2 factores de igual forma con rotación varimax y oblimin.
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.
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
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.
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
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.
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.