1  Inferencia paramétrica y no paramétrica

Iniciando el camino

Published

December 14, 2025

1.1 Introducciòn

Cargamos los paquetes necesarios y los datos. Usaremos el archivo testapp.sav proporcionado.

  • dplyr: para manipulación de datos.
  • psych: para análisis psicométricos y descriptivos.
  • nortest: para tests de normalidad.
  • coin: para tests no paramétricos.
  • expss: para tablas de resumen y tests de significancia.
  • kableExtra: para formateo de tablas.
  • purrr: para consolidar en una tabla de resultados las pruebas inferenciales.
Code
# Carga de paquetes
source('script.R')

# Opciones globales
options(scipen = 9, width = 100)

# Carga de datos desde el archivo CSV proporcionado

data <- read_spss("data/testapp.sav")


# Mostramos las primeras 5 filas

kable(head(data, 5)) %>%
  kable_styling(bootstrap_options = 'responsive')
ID_CASE LOADING SPEED SECURITY PRIVACY DESIGN RESPONSIVE MANAGEMENT INSTSETT OS AGENCY
1 16 25 23 41 41 38 50 21 1 1
2 16 20 30 46 45 25 84 40 2 1
3 26 32 36 53 52 25 87 32 2 1
4 38 39 22 42 51 26 63 14 2 2
5 34 35 36 43 47 23 38 31 2 1

1.2 Descripción de las escalas de medida

Las escalas de las variables en la base de datos son:

  • ID_CASE: Ordinal (o nominal si el orden no importa).
  • LOADING, SPEED, SECURITY, PRIVACY, DESIGN, RESPONSIVE, MANAGEMENT, INSTSETT: Métricas (de intervalo).
  • OS, AGENCY: Nominales.

1.3 Cálculo de descriptivos básicos

Existen múltiples formas de hacerlo. La más básica, sin necesidad de usar un paquete externo, es con summary().

Code
summary(data)
    ID_CASE          LOADING          SPEED          SECURITY        PRIVACY          DESIGN     
 Min.   :  1.00   Min.   : 6.00   Min.   : 9.00   Min.   : 7.00   Min.   :25.00   Min.   :32.00  
 1st Qu.: 25.75   1st Qu.:25.00   1st Qu.:29.75   1st Qu.:25.00   1st Qu.:39.00   1st Qu.:41.00  
 Median : 50.50   Median :34.00   Median :38.50   Median :30.00   Median :46.50   Median :48.50  
 Mean   : 50.50   Mean   :35.24   Mean   :39.47   Mean   :29.30   Mean   :46.10   Mean   :47.71  
 3rd Qu.: 75.25   3rd Qu.:46.00   3rd Qu.:50.00   3rd Qu.:34.25   3rd Qu.:53.25   3rd Qu.:54.00  
 Max.   :100.00   Max.   :61.00   Max.   :67.00   Max.   :46.00   Max.   :65.00   Max.   :68.00  
   RESPONSIVE      MANAGEMENT        INSTSETT           OS        AGENCY   
 Min.   :11.00   Min.   : 37.00   Min.   :11.00   Min.   :1   Min.   :1.0  
 1st Qu.:22.00   1st Qu.: 58.00   1st Qu.:22.00   1st Qu.:1   1st Qu.:1.0  
 Median :26.00   Median : 71.50   Median :26.00   Median :2   Median :2.0  
 Mean   :26.65   Mean   : 69.71   Mean   :26.65   Mean   :2   Mean   :1.6  
 3rd Qu.:30.00   3rd Qu.: 83.25   3rd Qu.:30.00   3rd Qu.:3   3rd Qu.:2.0  
 Max.   :46.00   Max.   :100.00   Max.   :46.00   Max.   :3   Max.   :2.0  

Sin embargo, el paquete psych nos da una salida más estructurada y completa en forma de tabla, muy utilizada en ciencias sociales.

Code
describe(select(data,2:9))
select(data, 2:9) 

 8  Variables      100  Observations
----------------------------------------------------------------------------------------------------
LOADING : SPEED LOADING CONTENTS 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       47    0.999    35.24       35    14.95    15.85    19.00    25.00    34.00 
     .75      .90      .95 
   46.00    53.00    55.05 

lowest :  6  9 10 11 13, highest: 56 58 59 60 61
----------------------------------------------------------------------------------------------------
SPEED : SPEED BROWSING 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       47    0.999    39.47     39.5     15.4    18.95    22.90    29.75    38.50 
     .75      .90      .95 
   50.00    57.10    62.05 

lowest :  9 14 15 17 18, highest: 60 62 63 66 67
----------------------------------------------------------------------------------------------------
SECURITY : DATA SECURITY 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       31    0.997     29.3     29.5    8.154    16.95    20.90    25.00    30.00 
     .75      .90      .95 
   34.25    37.00    40.00 

lowest :  7 11 15 16 17, highest: 39 40 43 45 46
----------------------------------------------------------------------------------------------------
PRIVACY : WORK DATA PRIVACY - PERSONAL DATA PRIVACY 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       35    0.998     46.1       46    10.35    32.00    34.90    39.00    46.50 
     .75      .90      .95 
   53.25    58.10    60.00 

lowest : 25 28 29 31 32, highest: 59 60 62 63 65
----------------------------------------------------------------------------------------------------
DESIGN : LAYOUT UX, GENERAL DESIGN 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       30    0.998    47.71     47.5    9.846    33.95    37.00    41.00    48.50 
     .75      .90      .95 
   54.00    59.10    61.00 

lowest : 32 33 34 36 37, highest: 60 61 62 67 68
----------------------------------------------------------------------------------------------------
RESPONSIVE : RESPONSIVE AND ADAPTATIVE SCREEN 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       29    0.996    26.65       26    8.572       14       17       22       26 
     .75      .90      .95 
      30       39       40 

lowest : 11 13 14 15 16, highest: 39 40 44 45 46
----------------------------------------------------------------------------------------------------
MANAGEMENT : MANAGEMENT OF DEVICE'S RESOURCES 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       46    0.999    69.71       70    18.24    44.95    47.90    58.00    71.50 
     .75      .90      .95 
   83.25    89.10    92.05 

lowest :  37  38  44  45  46, highest:  93  96  97  99 100
----------------------------------------------------------------------------------------------------
INSTSETT : INSTALLATION AND SETTINGS 
       n  missing distinct     Info     Mean  pMedian      Gmd      .05      .10      .25      .50 
     100        0       29    0.996    26.65       26    8.572       14       17       22       26 
     .75      .90      .95 
      30       39       40 

lowest : 11 13 14 15 16, highest: 39 40 44 45 46
----------------------------------------------------------------------------------------------------

1.4 Determinación de la normalidad y transformaciones

Realizamos el test de Kolmogorov-Smirnov con la corrección de Lilliefors sobre todas las variables métricas. Observaremos su p-valor para determinar si podemos asumir normalidad. Del mismo modo adjuntamos la prueba Shapiro-Wilk con la misma caracterización y estructura. Recordemos que Shapiro Wilk tiene una mayor potencia y “precisión” en los resultados.

Hipótesis: * H0: La distribución de la variable es normal. * H1: La distribución de la variable no es normal.

Code
#lillie.test(data$LOADING)
#lillie.test(data$SPEED)
#lillie.test(data$SECURITY)
#lillie.test(data$PRIVACY)
#lillie.test(data$DESIGN)
#lillie.test(data$RESPONSIVE)
#lillie.test(data$MANAGEMENT)
#lillie.test(data$INSTSETT)
## ---------
#shapiro.test(data$LOADING)
#shapiro.test(data$SPEED)
#shapiro.test(data$SECURITY)
#shapiro.test(data$PRIVACY)
#shapiro.test(data$DESIGN)
#shapiro.test(data$RESPONSIVE)
#shapiro.test(data$MANAGEMENT)
#shapiro.test(data$INSTSETT)

# Definir el vector de nombres de las columnas a analizar
columnas_a_testear <- c(
  "LOADING",
  "SPEED",
  "SECURITY",
  "PRIVACY",
  "DESIGN",
  "RESPONSIVE",
  "MANAGEMENT",
  "INSTSETT"
)

tabla_resultados <- map_dfr(columnas_a_testear, function(col_name) {
  # Extraer el vector de datos de la columna actual
  vector_datos <- data[[col_name]]
  
  # Aplicar los tests y extraer el p-valor
  # Usamos tryCatch para que si un test falla, no detenga el proceso
  p_valor_lillie <- tryCatch({
    lillie.test(vector_datos)$p.value
  }, error = function(e) {
    NA_real_
  })
  
  p_valor_shapiro <- tryCatch({
    shapiro.test(vector_datos)$p.value
  }, error = function(e) {
    NA_real_
  })
  
  # Devolver un tibble (un dataframe moderno) con una fila de resultados
  tibble(
    Variable = col_name,
    `P-valor KS-Lilliefors` = p_valor_lillie,
    `P-valor Shapiro-Wilk` = p_valor_shapiro
  )
})

# Mostrar la tabla de resultados de forma elegante
#    Usamos kable y kable_styling para una presentación profesional.
tabla_resultados %>%
  # Añadimos una columna para la decisión (asumiendo alpha = 0.05)
  mutate(`Normalidad (Shapiro-Wilk)` = ifelse(`P-valor Shapiro-Wilk` < 0.05, "No", "Sí")) %>%
  # Formateamos los números para que sean más legibles
  mutate(across(where(is.numeric), ~ format.pval(., digits = 3, eps = 0.001))) %>%
  kable(caption = "Resultados de los Tests de Normalidad") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  )
Resultados de los Tests de Normalidad
Variable P-valor KS-Lilliefors P-valor Shapiro-Wilk Normalidad (Shapiro-Wilk)
LOADING 0.371 0.210
SPEED 0.251 0.299
SECURITY 0.178 0.562
PRIVACY 0.134 0.320
DESIGN 0.145 0.074
RESPONSIVE <0.001 0.007 No
MANAGEMENT 0.041 0.028 No
INSTSETT <0.001 0.007 No

Conclusión: Con un nivel de significancia de 0.05, si el p-valor es menor que 0.05, rechazamos la hipótesis nula (H0). Vemos que para las variables RESPONSIVE, MANAGEMENT e INSTSETT, sus p-valores son muy bajos, por lo que no podemos considerar que sus distribuciones sean normales.

A continuación, realizamos transformaciones (raíz cuadrada, logaritmo base 10 y logaritmo neperiano) sobre estas tres variables para intentar normalizarlas.

Code
# Creación de variables transformadas
data$SQRTRESPONSIVE <- sqrt(data$RESPONSIVE)
data$SQRTMANAGEMENT <- sqrt(data$MANAGEMENT)
data$SQRTINSTSETT    <- sqrt(data$INSTSETT)

data$LOGRESPONSIVE <- log(data$RESPONSIVE + 1, 10)
data$LOGMANAGEMENT <- log(data$MANAGEMENT + 1, 10)
data$LOGINSTSETT    <- log(data$INSTSETT + 1, 10)

data$LNRESPONSIVE <- log(data$RESPONSIVE)
data$LNMANAGEMENT <- log(data$MANAGEMENT)
data$LNINSTSETT    <- log(data$INSTSETT)

# Nuevas pruebas de normalidad
#lillie.test(data$SQRTRESPONSIVE)
#lillie.test(data$SQRTMANAGEMENT)
#lillie.test(data$SQRTINSTSETT)
#lillie.test(data$LOGRESPONSIVE)
#lillie.test(data$LOGMANAGEMENT)
#lillie.test(data$LOGINSTSETT)
#lillie.test(data$LNRESPONSIVE)
#lillie.test(data$LNMANAGEMENT)
#lillie.test(data$LNINSTSETT)
## ---
#shapiro.test(data$SQRTRESPONSIVE)
#shapiro.test(data$SQRTMANAGEMENT)
#shapiro.test(data$SQRTINSTSETT)
#shapiro.test(data$LOGRESPONSIVE)
#shapiro.test(data$LOGMANAGEMENT)
#shapiro.test(data$LOGINSTSETT)
#shapiro.test(data$LNRESPONSIVE)
#shapiro.test(data$LNMANAGEMENT)
#shapiro.test(data$LNINSTSETT)

# 1. Definir el vector de nombres de las columnas a analizar
columnas_a_testear <- c(
  "SQRTRESPONSIVE",
  "SQRTMANAGEMENT",
  "SQRTINSTSETT",
  "LOGRESPONSIVE",
  "LOGMANAGEMENT",
  "LOGINSTSETT",
  "LNRESPONSIVE",
  "LNMANAGEMENT",
  "LNINSTSETT"
)
library(purrr)
tabla_resultados <- map_dfr(columnas_a_testear, function(col_name) {
  # Extraer el vector de datos de la columna actual
  vector_datos <- data[[col_name]]
  
  # Aplicar los tests y extraer el p-valor
  # Usamos tryCatch para que si un test falla, no detenga el proceso
  p_valor_lillie <- tryCatch({
    lillie.test(vector_datos)$p.value
  }, error = function(e) {
    NA_real_
  })
  
  p_valor_shapiro <- tryCatch({
    shapiro.test(vector_datos)$p.value
  }, error = function(e) {
    NA_real_
  })
  
  # Devolver un tibble (un dataframe moderno) con una fila de resultados
  tibble(
    Variable = col_name,
    `P-valor KS-Lilliefors` = p_valor_lillie,
    `P-valor Shapiro-Wilk` = p_valor_shapiro
  )
})

# 3. Mostrar la tabla de resultados de forma elegante
#    Usamos kable y kable_styling para una presentación profesional.
tabla_resultados %>%
  # Añadimos una columna para la decisión (asumiendo alpha = 0.05)
  mutate(`Normalidad (Shapiro-Wilk)` = ifelse(`P-valor Shapiro-Wilk` < 0.05, "No", "Sí")) %>%
  # Formateamos los números para que sean más legibles
  mutate(across(where(is.numeric), ~ format.pval(., digits = 3, eps = 0.001))) %>%
  kable(caption = "Resultados de los Tests de Normalidad") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  )
Resultados de los Tests de Normalidad
Variable P-valor KS-Lilliefors P-valor Shapiro-Wilk Normalidad (Shapiro-Wilk)
SQRTRESPONSIVE 0.032 0.086
SQRTMANAGEMENT 0.035 0.005 No
SQRTINSTSETT 0.032 0.086
LOGRESPONSIVE 0.005 0.039 No
LOGMANAGEMENT 0.004 <0.001 No
LOGINSTSETT 0.005 0.039 No
LNRESPONSIVE 0.004 0.031 No
LNMANAGEMENT 0.004 <0.001 No
LNINSTSETT 0.004 0.031 No

Conclusión: Tras realizar las transformaciones, observamos que los p-valores de los tests de normalidad siguen siendo significativamente bajos. Aunque alguno de ellos nos permitiría no rechazar la normalidad, creeemos más acertado dado que existe divergencia entre las dos pruebas, ser muy conservadores en este aspecto. Por lo tanto, ninguna de las transformaciones lineales ha conseguido normalizar estas variables. Deberemos tratarlas como no paramétricas.

Para acompañar el análisis, cremos los gráficos QQPLOT …

Code
#' Crea un gráfico Q-Q de normalidad para una columna específica de un dataframe.
#'
#' @param data El dataframe que contiene los datos.
#' @param column El nombre de la columna a analizar. Se puede pasar sin comillas
#'        (ej. mi_columna) o como una cadena de texto (ej. "mi_columna").
#'
#' @return Un objeto de ggplot que representa el gráfico Q-Q.
#'

create_qqplot <- function(data, column) {
  
  col_name_str <- rlang::as_name(rlang::enquo(column))

  # Comprobamos que la columna exista en el dataframe
  if (!col_name_str %in% names(data)) {
    stop(paste("La columna '", col_name_str, "' no se encuentra en el dataframe."))
  }
  
  # --- Creación del Gráfico ---
  p <- ggplot(data, aes(sample = {{ column }})) +
    # El operador {{ }} es la forma moderna de pasar un argumento de función a aes()
    
    geom_qq(color = "steelblue", alpha = 0.8) + # Dibuja los puntos
    geom_qq_line(color = "red", linewidth = 1) +   # Dibuja la línea de referencia
    
    # Personalización de títulos y etiquetas
    labs(
      title = paste("Gráfico Q-Q de Normalidad para:", col_name_str),
      x = "Cuantiles Teóricos (Distribución Normal)",
      y = "Cuantiles de la Muestra"
    ) +
    
    # Tema limpio
    ggthemes::theme_economist() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
    )
  
  return(p)
}

create_qqplot(data = data, column = LOADING)

Code
create_qqplot(data = data, column = SPEED)

Code
create_qqplot(data = data, column = SECURITY)

Code
create_qqplot(data = data, column = PRIVACY)

Code
create_qqplot(data = data, column = DESIGN)

Code
create_qqplot(data = data, column = RESPONSIVE)

Code
create_qqplot(data = data, column = MANAGEMENT)

Code
create_qqplot(data = data, column = INSTSETT)               

1.4.1 Interpretación Visual

  • Si los puntos azules se ajustan estrechamente a la línea roja, es una fuerte indicación de que los datos provienen de una distribución normal.
  • Si los puntos se desvían sistemáticamente de la línea (formando una curva), los datos no son normales.
Code
#' Crea un gráfico "Detrended Normal Q-Q" para una columna específica.
#'
#' Este gráfico muestra las desviaciones de la normalidad, replicando el
#' "Detrended Normal Q-Q Plot" de SPSS.
#'
#' @param data El dataframe que contiene los datos.
#' @param column El nombre de la columna a analizar (sin comillas).
#'
#' @return Un objeto de ggplot que representa el gráfico.
#'
create_detrended_qqplot <- function(data, column) {
  
  # --- 1. Capturar y validar la entrada ---

    col_name_str <- rlang::as_name(rlang::enquo(column))
  if (!col_name_str %in% names(data)) {
    stop(paste("La columna '", col_name_str, "' no se encuentra en el dataframe."))
  }
  
    # Extraer el vector de datos y eliminar los NAs
  y <- data[[col_name_str]]
  y <- y[!is.na(y)]
  
  # --- 2. Calcular los componentes del Q-Q plot ---
  # Ordenar los datos de la muestra
  y_sorted <- sort(y)
  
  # Calcular los cuantiles teóricos de una distribución normal estándar
  n <- length(y)
  theoretical_quantiles <- qnorm(ppoints(n))
  
  # Estandarizar los datos de la muestra para que sean comparables
  # (media 0, desviación estándar 1)
  y_standardized <- (y_sorted - mean(y)) / sd(y)
  
  # --- 3. ¡LA MAGIA! Calcular la "detrended" difference ---
  # La diferencia es simplemente el cuantil de la muestra menos el cuantil teórico
  detrended_difference <- y_standardized - theoretical_quantiles
  
  # Crear un dataframe para ggplot
  plot_data <- data.frame(
    theoretical = theoretical_quantiles,
    difference = detrended_difference
  )
  
  # --- 4. Creación del Gráfico ---
  p <- ggplot(plot_data, aes(x = theoretical, y = difference)) +
    # Añadimos una línea de referencia horizontal en y=0
    geom_hline(yintercept = 0, color = "red", linewidth = 1, linetype = "dashed") +
    
    # Dibujamos los puntos de la diferencia
    geom_point(color = "steelblue", alpha = 0.8, size = 2.5) +
    
    # Personalización de títulos y etiquetas
    labs(
      title = paste("Detrended Normal Q-Q Plot para:", col_name_str),
      subtitle = "Las desviaciones de la línea horizontal indican no-normalidad",
      x = "Cuantiles Teóricos (Distribución Normal)",
      y = "Desviación de la Normalidad"
    ) +
    
    # Tema limpio
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      plot.subtitle = element_text(hjust = 0.5, size = 10)
    )
  
  return(p)
}

create_detrended_qqplot(data = data, column = LOADING)

Code
create_detrended_qqplot(data = data, column = SPEED)

Code
create_detrended_qqplot(data = data, column = SECURITY)

Code
create_detrended_qqplot(data = data, column = PRIVACY)

Code
create_detrended_qqplot(data = data, column = DESIGN)

Code
create_detrended_qqplot(data = data, column = RESPONSIVE)

Code
create_detrended_qqplot(data = data, column = MANAGEMENT)

Code
create_detrended_qqplot(data = data, column = INSTSETT)       

1.4.2 Interpretación Visual del Gráfico “Detrended”

  • Si los datos son normales: Los puntos se distribuirán de forma aleatoria y sin un patrón claro alrededor de la línea horizontal roja en y=0. No deberían formar ninguna curva o estructura discernible.
  • Si los datos NO son normales: Los puntos formarán un patrón sistemático. Por ejemplo:
    • Asimetría a la derecha (Right Skew): Los puntos formarán una curva en forma de “U” o de sonrisa.
    • Asimetría a la izquierda (Left Skew): Los puntos formarán una curva en forma de “U” invertida o de ceño fruncido.
    • Colas pesadas (Heavy Tails): Los puntos formarán una “S” invertida.
    • Colas ligeras (Light Tails): Los puntos formarán una “S” normal.

1.5 Diferencias de medias por Sistema Operativo (OS)

Para determinar si existen diferencias en las medias de las variables métricas con respecto a los grupos de OS, usaremos el paquete expss para generar una tabla de medias y realizar un test de significancia (ANOVA en este caso).

Code
data %>% 
  tab_cols(total(), OS) %>% 
  tab_cells(LOADING, SPEED, SECURITY, PRIVACY, DESIGN) %>% 
  tab_stat_mean_sd_n() %>%
  tab_last_sig_means(keep = 'means') %>%
  tab_pivot() %>%
  as.datatable_widget()

Conclusión Comercial: Se observan diferencias estadísticamente significativas en las valoraciones de LOADING, SPEED, PRIVACY y DESIGN entre los diferentes sistemas operativos. La variable SECURITY es la única que no presenta diferencias significativas. Analizando las medias, podemos ver qué sistema operativo obtiene mejores o peores valoraciones en cada aspecto, lo que puede guiar esfuerzos de optimización específicos para cada plataforma.

También podríamos haberlo hecho siguiendo las pautas naturales de Levene test y posteriormente t-test para todos los pares (SPSS). Esto se debería repetir para todos los pares de OS y para todas las variables.

Code
test_levene <- leveneTest(LOADING ~ factor(OS), data = filter(data, OS %in% c(1,2)))
print(test_levene)
      Df   F value    Pr(>F)
group  1 0.2167042 0.6431429
      64        NA        NA
Code
p_valor_levene <- test_levene$`Pr(>F)`[1]

if (p_valor_levene >= 0.05) {
  print("Resultado de Levene (p >= 0.05): Las varianzas se asumen iguales.\n")
  print("Ejecutando t-test de Student (var.equal = TRUE).\n\n")
  test_t <- t.test(LOADING ~ factor(OS), data = filter(data, OS %in% c(1,2)), var.equal = TRUE)
} else {
  print("Resultado de Levene (p < 0.05): Las varianzas se asumen diferentes.\n")
  print("Ejecutando t-test de Welch (var.equal = FALSE).\n\n")
  test_t <- t.test(LOADING ~ factor(OS), data = filter(data, OS %in% c(1,2)), var.equal = FALSE)
}
[1] "Resultado de Levene (p >= 0.05): Las varianzas se asumen iguales.\n"
[1] "Ejecutando t-test de Student (var.equal = TRUE).\n\n"
Code
print(test_t)

Results of Hypothesis Test
--------------------------

Null Hypothesis:                 difference in means between group 1 and group 2 = 0

Alternative Hypothesis:          True difference in means between group 1 and group 2 is not equal to 0

Test Name:                        Two Sample t-test

Estimated Parameter(s):          mean in group 1 = 25.08824
                                 mean in group 2 = 34.21875

Data:                            LOADING by factor(OS)

Test Statistic:                  t = -3.847281

Test Statistic Parameter:        df = 64

P-value:                         0.0002779577

95% Confidence Interval:         LCL = -13.871603
                                 UCL =  -4.389427

1.6 Diferencias en variables no normales por Tipo de Tester (AGENCY)

Dado que RESPONSIVE, MANAGEMENT e INSTSETT no siguen una distribución normal, para comparar las diferencias entre los dos grupos de AGENCY debemos usar un test no paramétrico. El test adecuado es el Test de Wilcoxon-Mann-Whitney (equivalente al t.test para datos no paramétricos).

Code
wilcox.test(data$RESPONSIVE ~ data$AGENCY, data = data, distribution = "exact", conf.int = 0.95)

    Wilcoxon rank sum test with continuity correction

data:  data$RESPONSIVE by data$AGENCY
W = 1189.5, p-value = 0.9438
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -2.999945  2.999982
sample estimates:
difference in location 
        -0.00005540274 
Code
wilcox.test(data$MANAGEMENT ~ data$AGENCY, data = data, distribution = "exact", conf.int = 0.95)

    Wilcoxon rank sum test with continuity correction

data:  data$MANAGEMENT by data$AGENCY
W = 1190, p-value = 0.9467
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -6.999971  6.999979
sample estimates:
difference in location 
         -0.0000137715 
Code
wilcox.test(data$INSTSETT ~ data$AGENCY, data = data, distribution = "exact", conf.int = 0.95)

    Wilcoxon rank sum test with continuity correction

data:  data$INSTSETT by data$AGENCY
W = 1287.5, p-value = 0.5396
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -1.999987  3.999994
sample estimates:
difference in location 
             0.9999971 

Conclusión Comercial: En los tres casos, los p-valores son mayores que 0.05. Por lo tanto, no podemos rechazar la hipótesis nula de igualdad. Esto significa que no existen diferencias estadísticamente significativas en las valoraciones de RESPONSIVE, MANAGEMENT e INSTSETT entre las agencias cualitativas y cuantitativas. El tipo de agencia no parece influir en la percepción de estos atributos de la aplicación.

1.7 Relación entre variables métricas con normalidad

Para analizar la relación entre las variables métricas que sí asumimos como normales (LOADING a DESIGN), calculamos el coeficiente de correlación de Pearson.

Code
options(scipen = 9, digits = 5, width = 9999)

# Test de correlación
corr.test(
  select(data, LOADING:DESIGN),
  use = "pairwise",
  method = "pearson",
  alpha = .01,
  ci = TRUE
)
Call:corr.test(x = select(data, LOADING:DESIGN), use = "pairwise", 
    method = "pearson", alpha = 0.01, ci = TRUE)
Correlation matrix 
         LOADING SPEED SECURITY PRIVACY DESIGN
LOADING     1.00  0.97     0.59    0.67   0.65
SPEED       0.97  1.00     0.57    0.66   0.62
SECURITY    0.59  0.57     1.00    0.67   0.58
PRIVACY     0.67  0.66     0.67    1.00   0.71
DESIGN      0.65  0.62     0.58    0.71   1.00
Sample Size 
[1] 100
Probability values (Entries above the diagonal are adjusted for multiple tests.) 
         LOADING SPEED SECURITY PRIVACY DESIGN
LOADING        0     0        0       0      0
SPEED          0     0        0       0      0
SECURITY       0     0        0       0      0
PRIVACY        0     0        0       0      0
DESIGN         0     0        0       0      0

 To see confidence intervals of the correlations, print with the short=FALSE option
Code
# Matriz de gráficos de dispersión y correlaciones
pairs.panels(select(data, LOADING:DESIGN))

1.8 Relación entre variables métricas sin normalidad

Para las variables que no son normales (RESPONSIVE, MANAGEMENT, INSTSETT), debemos usar coeficientes de correlación no paramétricos, como Spearman o Kendall.

Code
options(scipen = 9, digits = 5, width = 9999)

# Correlación de Spearman
corr.test(select(data, RESPONSIVE:INSTSETT), use = "pairwise", method = "spearman", alpha = .01, ci = TRUE)
Call:corr.test(x = select(data, RESPONSIVE:INSTSETT), use = "pairwise", 
    method = "spearman", alpha = 0.01, ci = TRUE)
Correlation matrix 
           RESPONSIVE MANAGEMENT INSTSETT
RESPONSIVE       1.00       0.09    -0.03
MANAGEMENT       0.09       1.00     0.23
INSTSETT        -0.03       0.23     1.00
Sample Size 
[1] 100
Probability values (Entries above the diagonal are adjusted for multiple tests.) 
           RESPONSIVE MANAGEMENT INSTSETT
RESPONSIVE       0.00       0.70     0.74
MANAGEMENT       0.35       0.00     0.07
INSTSETT         0.74       0.02     0.00

 To see confidence intervals of the correlations, print with the short=FALSE option
Code
pairs.panels(select(data, RESPONSIVE:INSTSETT), method = "spearman")

Code
# Correlación de Kendall
corr.test(select(data, RESPONSIVE:INSTSETT), use = "pairwise", method = "kendall", alpha = .01, ci = TRUE)
Call:corr.test(x = select(data, RESPONSIVE:INSTSETT), use = "pairwise", 
    method = "kendall", alpha = 0.01, ci = TRUE)
Correlation matrix 
           RESPONSIVE MANAGEMENT INSTSETT
RESPONSIVE       1.00       0.07    -0.02
MANAGEMENT       0.07       1.00     0.15
INSTSETT        -0.02       0.15     1.00
Sample Size 
[1] 100
Probability values (Entries above the diagonal are adjusted for multiple tests.) 
           RESPONSIVE MANAGEMENT INSTSETT
RESPONSIVE       0.00       1.00     1.00
MANAGEMENT       0.52       0.00     0.43
INSTSETT         0.87       0.14     0.00

 To see confidence intervals of the correlations, print with the short=FALSE option
Code
pairs.panels(select(data, RESPONSIVE:INSTSETT), method = "kendall")

1.9 Dependencia entre variables métricas recodificadas y tipo de tester

Para analizar la dependencia entre las variables no paramétricas y el tipo de tester, primero las recodificamos en tres niveles (Bajo, Medio, Alto) basándonos en sus cuartiles.

Code
# Recodificación de variables
data = data %>% compute(
    RRESPONSIVE = expss::recode(
        RESPONSIVE,
        lo %thru% fivenum(RESPONSIVE)[2] ~ 1,
        (fivenum(RESPONSIVE)[2] + 0.001) %thru% fivenum(RESPONSIVE)[3] ~ 2,
        (fivenum(RESPONSIVE)[3] + 0.001) %thru% hi ~ 3
    ),
    RMANAGEMENT = expss::recode(
        MANAGEMENT,
        lo %thru% fivenum(MANAGEMENT)[2] ~ 1,
        (fivenum(MANAGEMENT)[2] + 0.001) %thru% fivenum(MANAGEMENT)[3] ~ 2,
        (fivenum(MANAGEMENT)[3] + 0.001) %thru% hi ~ 3
    ),
    RINSTSETT = expss::recode(
        INSTSETT,
        lo %thru% fivenum(INSTSETT)[2] ~ 1,
        (fivenum(INSTSETT)[2] + 0.001) %thru% fivenum(INSTSETT)[3] ~ 2,
        (fivenum(INSTSETT)[3] + 0.001) %thru% hi ~ 3
    )
)

# Aplicar etiquetas a los nuevos niveles
val_lab(data$RRESPONSIVE) = num_lab("
    1 Bajo
    2 Medio
    3 Alto
    ")
val_lab(data$RMANAGEMENT) =num_lab("
    1 Bajo
    2 Medio
    3 Alto
    ")
val_lab(data$RINSTSETT) = num_lab("
    1 Bajo
    2 Medio
    3 Alto
    ")

# Tabla de contingencia con porcentajes y test de significancia (Chi-cuadrado)
options(digits = 3, width = 9999)
data %>% 
     tab_cols(total(), AGENCY) %>% 
     tab_cells(RRESPONSIVE, RMANAGEMENT, RINSTSETT) %>% 
     tab_stat_cases() %>% 
     tab_last_sig_cases() %>% 
     tab_pivot() %>%
    as.datatable_widget()

Conclusión: El test de Chi-cuadrado nos indica si existe una relación de dependencia entre el nivel de valoración (Bajo, Medio, Alto) y el tipo de agencia. Si la significancia es menor a 0.05, podemos concluir que el tipo de agencia está relacionado con la probabilidad de que la valoración de ese atributo sea alta, media o baja.

Otra forma de hacerlo más estándar y utilizando R-base sería …

Code
table(data$RMANAGEMENT, data$AGENCY)
       
        QUANTI QUALI
  Bajo      11    15
  Medio      9    15
  Alto      20    30
Code
chisq.test(table(data$RRESPONSIVE, data$AGENCY))

    Pearson's Chi-squared test

data:  table(data$RRESPONSIVE, data$AGENCY)
X-squared = 0.7, df = 2, p-value = 0.7
Code
table(data$RMANAGEMENT, data$AGENCY)
       
        QUANTI QUALI
  Bajo      11    15
  Medio      9    15
  Alto      20    30
Code
chisq.test(table(data$RMANAGEMENT, data$AGENCY),correct=)

    Pearson's Chi-squared test

data:  table(data$RMANAGEMENT, data$AGENCY)
X-squared = 0.1, df = 2, p-value = 0.9
Code
table(data$RINSTSETT, data$AGENCY)
       
        QUANTI QUALI
  Bajo      10    16
  Medio     12    19
  Alto      18    25
Code
chisq.test(table(data$RINSTSETT, data$AGENCY))

    Pearson's Chi-squared test

data:  table(data$RINSTSETT, data$AGENCY)
X-squared = 0.1, df = 2, p-value = 0.9

Wickham (2023) Wickham and Henry (2025) Kassambara (2025) Lin (2025) Kunst (2022) Komsta (2022) Millard (2025) Dinno (2024) Revelle (2025) Husson et al. (2025) Kassambara and Mundt (2020) Greenacre and Nenadic (2020) Bryan (2025) Wei and Simko (2024) Pedersen (2025) Lüdecke, Makowski, Ben-Shachar, et al. (2025) Hendricks (2015) Kuhn and Wickham (2025) Robin et al. (2025) Kuhn (2024) Lüdecke, Makowski, Patil, et al. (2025) Revelle (2025) Gross and Ligges (2015) Hothorn et al. (2023) Zhu (2024) Fox, Weisberg, and Price (2024) Wickham, Hester, and Bryan (2025) Demin (2025a) Demin (2025b) Xie et al. (2025)“, Charrad et al. (2022)”, Maechler et al. (2025)“, Demin (2025a)”, Demin (2025b)“, Fox, Weisberg, and Price (2024)”, Hothorn et al. (2022)“, Gross and Ligges (2015)”, Harrell Jr (2025)“, Pedersen (2025)