Sys.setlocale("LC_ALL", "es_ES.UTF-8")
[1] "LC_COLLATE=es_ES.UTF-8;LC_CTYPE=es_ES.UTF-8;LC_MONETARY=es_ES.UTF-8;LC_NUMERIC=C;LC_TIME=es_ES.UTF-8"

Presentar un resumen de las PRUEBAS ROBUSTAS (enumeradas a continuación) con 1 EJEMPLO en R para cada una de ellas y completarlo con el documento que se adjunta (“Robust statistical methods in R using WRS2 package”).

1 PRUEBAS ROBUSTAS

Las pruebas robustas son pruebas estadísticas que se usan cuando los datos que se quieren analizar no siguen la distribución normal, tienen outliers (valores atípicos) o siguen distribuciones de cola gruesa (con gran asimetría). Esto se debe a que las pruebas robustas no hacen suposiciones como lo hacen las pruebas paramétricas.

Debido a que pueden ser usados en situaciones que se dan más comúnmente en la naturaleza, son más útiles para comprender los datos de una forma más profunda, matizada y precisa.

Para realizar estas pruebas robustas, la libreria WRS2 de R es muy útil

Alternativas que se usan en las pruebas robustas

  • Media recortada: Es una alternativa a la media aritmética. Al calcular una media recortada al 30%, quiere decir que se reduce el 30% en el extremo inferior y en el extremo superior. Al calcular la media recortada al 50% se obtiene la mediana. Este cálculo se puede realizar mediante la función trim de la librería WRS2.
  • Media Winsorizada: Es una alternativa en el que se le da menos peso a las observaciones en las colas de la distribución y mayor peso a las observaciones del centro. Entonces para obtener la media winsorizada se usa la distribución winsorizada. Este cálculo se puede realizar mediante la función winmean de la librería WRS2.

1.1 Prueba para 1 muestra

Para realizar pruebas robustas para 1 sola muestra, una de las pruebas más comunes es la prueba de Wilcoxon, que se utiliza para comparar la mediana de una muestra con un valor hipotético. Se usa esta prueba debido a que no necesita suposiciones como la distribución normal, y también puede ser usado cuando se encuentran valores atípicos en los datos.

1.1.1 Ejemplo

Se dispone de una muestra de datos x que se sospecha que no sigue una distribución normal. El objetivo es realizar una prueba de hipótesis para determinar si la mediana de la muestra es significativamente diferente de un valor hipotético de 10.

\[\begin{cases} H_0 : Me_m = 10 \\ H_1 : Me_m \neq 10 \end{cases}\]

set.seed(123)
x <- rnorm (50, mean = 12, sd = 3)

test_wilcoxon <- wilcox.test (x, mu = 10, alternative = "two.sided")
test_wilcoxon

    Wilcoxon signed rank test with continuity correction

data:  x
V = 1093, p-value = 1.122e-05
alternative hypothesis: true location is not equal to 10

Valor p = 1.121878e-05 Se recaza H_O con un nivel de significancia del 5 t, sugiriendo que la mediana de la muestra NO es igual a 10.

Volver al inicio

1.2 Prueba para 2 muestras

Las pruebas robustas para 2 muestras son una muy buena forma de determinar diferencias entre grupos cuando los datos no siguen una distribución normal o hay presencia de valores atípicos. Para probar estas diferencias, existen dos situaciones diferentes, cuando las muestras son independientes o cuando estas son pareadas.

1.2.1 Muestras independientes

Para el caso de tratar muestras independientes, Yuen propuso una prueba estadística para medias recortadas de 2 muestras, sin necesidad de igualdad de varianzas. Este test sigue la distribución t. También puede ser realizado sin necesidad de usar medias recortadas lo que convierte la prueba en las pruebas t de Welch con varianzas diferentes.

1.2.1.1 Ejemplo

Sabiendo que en el dataset eurosoccer de la librería WRS2 se reúnen los datos de las 5 principales ligas europeas de fútbol, determinar si existen diferencias significativas entre los goles anotados entre las ligas de Los Países Bajos y Alemania.

Viendo que la cantidad de goles anotados de una liga no tiene ninguna relación y por lo tanto no afecta en los goles anotados de otra liga, se asume que las 2 muestras son independientes.

library (WRS2)
data (eurosoccer)
data = eurosoccer

españa = data [data$League == "Spain", ]
alemania = data [data$League == "Germany", ]
esp_ger = rbind (españa, alemania)
esp_ger$League = droplevels (esp_ger$League) #Elimina los niveles no utilizados en la columna League del nuevo conjunto de datos esp_ger

tabla = data %>% datatable (extensions = "Buttons", filter = "top",
                            options = list (
                              scrollY = "200px",
                              pageLength = 20, # Mostrar solo 10 filas por página
                              lengthMenu = c(10, 20, 40), # Opciones de selección de cantidad de filas por página
                              ordering = TRUE, # Permitir ordenamiento de columnas
                              dom = '1Bfrtip', # Definir la disposición de los elementos de la tabla
                              buttons = c('copy', 'csv', 'excel', 'pdf', 'print') # Agregar botones de exportación
                            ),
                            class = 'compact cell-border stripe white-space nowrap' # Estilo de borde de celda y filas alternas resaltadas
                            )
tabla
resultado <- pb2gen (GoalsScored ~ League, data = esp_ger, est = "median")
resultado
Call:
pb2gen(formula = GoalsScored ~ League, data = esp_ger, est = "median")

Test statistic: 1, p-value = 0.80968
95% confidence interval:
-12    13 

p valor = 0.8096828 Se acepta HO con un nivel de significancia del 5 t, sugiriendo que la mediana de los goles anotados en la liga Espanola y la Alemana es igual

# Calcular un valor de posición 'y' para cada anotación
comparaciones_significativas <- data.frame (
  grupo1 = "Spain",
  grupo2 = "Germany",
  p_value = resultado$p.value)

comparaciones_significativas
  grupo1  grupo2   p_value
1  Spain Germany 0.8096828
# Agregar una columna para las anotaciones de significancia basada en los p-valores
comparaciones_significativas$annotation <- ifelse(
  comparaciones_significativas$p_value < 0.001, ' *** ',
  ifelse(
    comparaciones_significativas$p_value < 0.01, ' ** ',
    ifelse(
      comparaciones_significativas$p_value < 0.05, '*', 'ns'
    )
  )
)
  
comparaciones_significativas
  grupo1  grupo2   p_value annotation
1  Spain Germany 0.8096828         ns
max_valor = max (data$GoalsScored, na.rm = TRUE)
espacio_entre_anotaciones = max_valor * 0.1 # ajusta este valor según sea necesario
max_valor
[1] 105
espacio_entre_anotaciones
[1] 10.5
# Agregar las posiciones 'y' al dataframe
comparaciones_significativas$y_position <- seq(from = max_valor + espacio_entre_anotaciones,
                                               by = espacio_entre_anotaciones,
                                               length.out = nrow(comparaciones_significativas))
comparaciones_significativas
  grupo1  grupo2   p_value annotation y_position
1  Spain Germany 0.8096828         ns      115.5
# Creando el gráfico base de cajas
p <- ggplot (esp_ger, aes (x = League, y = GoalsScored) ) +
  geom_boxplot (fill = "#5C7285", color = "#5C7285", alpha = 0.5) +
  theme_bw () +
  labs (x = "Liga", y = "Goles Anotados") +
  ggtitle ("Eurosoccer") +
  theme (
    plot.title = element_text (size = 20, face = "bold", hjust = 0.05),
    axis.text.x = element_text (size = 12),
    axis.text.y = element_text (size = 12),
    axis.title = element_text (size = 14, face = "bold"),
    legend.position = "none")

# Añadiendo las anotaciones de significancia usando geom_signif
p <- p + geom_signif(
  data = comparaciones_significativas,
  aes(xmin = grupo1, xmax = grupo2, annotations = annotation, y_position = y_position),
  manual = TRUE,
  )
  
# Ajustar los limites del eje y para acomodar las anotaciones
p <- p + ylim(0, max(comparaciones_significativas$y_position) * 1.1)

# Imprimir el gráfico
p

Volver al inicio

1.2.2 Muestras pareadas

Al igual que en el caso de muestras independientes, en la librería WRS2 también hay funciones útiles para poder determinar diferencias entre muestras pareadas. En este caso, la función yuend es muy interesante. Esta función realiza pruebas de las medias recortadas en el caso de 2 muestras pareadas. Para usar la función se puede cambiar el porcentaje de la media recortada mediante tr = … pero la función por defecto usa tr = 0.2.

1.2.2.1 Ejemplo

Interesa comparar pesos antes y después de un tratamiento para la anorexia en un grupo de tratamiento familiar, para poder determinar si el tratamiento es eficaz para la ganancia de peso.

En este caso, como se quiere ver la diferencia de peso antes y después del tratamiento, se habla de muestras pareadas.

\[\begin{cases} H_0 : Me_{pre} = Me_{post} \\ H_1 : Me_{pre} \neq Me_{post} \end{cases}\]

library (MASS)

data (anorexia)
data = anorexia

tabla = data %>% datatable (extensions = "Buttons", filter = "top",
                            options = list (
                              scrollY = "200px",
                              pageLength = 20, # Mostrar solo 10 filas por página
                              lengthMenu = c(10, 20, 40), # Opciones de seleoción de cantidad de filas por página
                              ordering = TRUE, # Permitir ordenamiento de columnas
                              dom = '1Bfrtip', # Definir la disposición de los elementos de la tabla
                              buttons = c('copy', 'cav', 'excel', 'pdf', 'print') # Agregar botones de exportación
                            ),
                            class = 'compact cell-border stripe white-space nowrap' # Estilo de borde de celda y filas alternas resaltadas
                            )
tabla
#FT = Tratamiento familiar
anorexia_FT = data [data$Treat == "FT", ]

library (tidyr)
library (dplyr)

datos_FT <- pivot_longer (anorexia_FT, cols = c(Prewt, Postwt) , names_to = "Tiempo", values_to = "Peso")
head (datos_FT)
# A tibble: 6 × 3
  Treat Tiempo  Peso
  <fct> <chr>  <dbl>
1 FT    Prewt   83.8
2 FT    Postwt  95.2
3 FT    Prewt   83.3
4 FT    Postwt  94.3
5 FT    Prewt   86  
6 FT    Postwt  91.5
datos_FT$Tiempo = factor (datos_FT$Tiempo, levels = c("Prewt", "Postwt" ) )
head (datos_FT)
# A tibble: 6 × 3
  Treat Tiempo  Peso
  <fct> <fct>  <dbl>
1 FT    Prewt   83.8
2 FT    Postwt  95.2
3 FT    Prewt   83.3
4 FT    Postwt  94.3
5 FT    Prewt   86  
6 FT    Postwt  91.5
FT_pre = datos_FT$Peso [datos_FT$Tiempo == "Prewt"]
FT_post = datos_FT$Peso [datos_FT$Tiempo == "Postwt"]

resultado <- yuend (FT_pre, FT_post)
resultado
Call:
yuend(x = FT_pre, y = FT_post)

Test statistic: -3.829 (df = 10), p-value = 0.00332

Trimmed mean difference:  -8.56364 
95 percent confidence interval:
-13.5469     -3.5804 

Explanatory measure of effect size: 0.6 
# Caloular un valor de posición 'y' para cada anotación
comparaciones_significativas <- data.frame (
  grupo1 = "Prewt",
  grupo2 = "Postwt",
  p_value = resultado$p.value)

# Agregar una columna para las anotaciones de significancia basada en los p-valores
comparaciones_significativas$annotation <- ifelse (
  comparaciones_significativas$p_value < 0.001, ' *** ',
  ifelse (
    comparaciones_significativas$p_value < 0.01, ' ** ',
    ifelse (
      comparaciones_significativas$p_value < 0.05, '*', 'ns'
    )
  )
)

max_valor = max (datos_FT$Peso, na.rm = TRUE)
espacio_entre_anotaciones = max_valor * 0.10 # ajusta este valor segun sea necesario

# Agregar las posiciones 'y' al dataframe
comparaciones_significativas$y_position <- seq(from = max_valor + espacio_entre_anotaciones/5,
                                               by = espacio_entre_anotaciones,
                                               length.out = nrow(comparaciones_significativas))

# Creando el gráfico base de cajas
p <- ggplot (datos_FT, aes (x = Tiempo, y = Peso) ) +
  geom_boxplot (fill = "#5C7285", color = "#5C7285", alpha = 0.5) +
  theme_bw () +
  labs (x = "Momento del tratamiento", y = "Peso del paciente") +
  ggtitle ("Tratamiento familiar de anorexia") +
  theme (
    plot.title = element_text (size = 20, face = "bold", hjust = 0.05),
    axis.text.x = element_text (size = 12),
    axis.text.y = element_text (size = 12),
    axis.title = element_text (size = 14, face = "bold"),
    legend.position = "none")

# Añadiendo las anotaciones de significancia usando geom signif
p <- p + geom_signif (
  data = comparaciones_significativas,
  aes (xmin = grupo1, xmax = grupo2, annotations = annotation, y_position = y_position) ,
  manual = TRUE,)

# Ajustar los limites del eje y para acomodar las anotaciones
p <- p + ylim(70, max(comparaciones_significativas$y_position) * 1.05)

# Imprimir el gráfico
p

Volver al inicio

1.3 Prueba para k muestras (ANOVA robusto de 1 via)

Un ANOVA robusto de 1 vía es una versión de la prueba ANOVA diseñada para manejar datos que no cumplen con los supuestos de normalidad y homogeneidad de varianza. Utiliza métodos robustos para calcular las estimaciones de los parámetros y las pruebas de hipótesis, lo que lo hace menos sensible a los valores atípicos y a las desviaciones de los supuestos.

1.3.1 ANOVA robusto inter-sujetos

Para realizar ANOVA robusto inter-sujetos primero hay que fijar que se quiere comparar.

  • Si se quieren comparar las medianas: Para esto se usa la función mediway, que realiza un ANOVA de 1 vía sin necesidad de asumir igualdad de varianzas.
  • Si se quieren comparar las medias recortadas: Para esto se usa la función t1way, que realiza un ANOVA de 1 vía usando medias recortadas y sin necesidad de asumir igualdad de varianzas. Usa una generalización del método de Welch. En el caso de que existan diferencias se pueden realizar test posthoc mediante el comando lincon.

1.3.1.1 Ejemplo

Para este ejemplo se volverá a usar el dataset eurosoccer solo que en vez de comparar los datos de solo 2 ligas europeas, se comparan la cantidad de goles anotados de todas las ligas europeas.

library (WRS2)
data (eurosoccer)
data = eurosoccer

tabla = data %>% datatable (extensions = "Buttons", filter = "top",
                           options = list (
                             scrollY = "200px",
                             pageLength = 20, # Mostrar solo 10 filas por página
                             lengthMenu = c(10, 20, 40), # Opciones de selección de oantidad de filas por página
                             ordering = TRUE, # Permitir ordenamiento de columnas
                             dom = 'lBfrtip', # Definir la disposición de los elementos de la tabla
                             buttons = c('copy', 'csv', 'excel', 'pdf', 'print') # Agregar botones de exportación
                             ),
                           class = 'compact cell-border stripe white-space nowrap' # Estilo de borde de celda y filas alternas resaltadas
                           )
tabla

Primero se comparan las medianas con la función med1way

resultado_med <- med1way (GoalsScored ~ League, data = data)
resultado_med
Call:
med1way(formula = GoalsScored ~ League, data = data)

Test statistic F: 1.0397 
Critical value: 2.2442 
p-value: 0.301 
p_thresh = 0.05
if (resultado$p.value > p_thresh) {
  cat ("p valor =", resultado_med$p.value, "\n")
  cat ("Se acepta HO con un nivel de significancia del", p_thresh*100, "%, sugiriendo quela mediana de los goles anotados de las ligas europeas es igual")
  } else{
    cat ("p valor =", resultado_med$p.value, "\n")
    cat ("Se rechaza HO con un nivel de significancia del", p_thresh*100, "%, sugiriendo que la mediana de los goles anotados de las ligas europeas NO es igual")
  }
p valor = 0.301 
Se rechaza HO con un nivel de significancia del 5 %, sugiriendo que la mediana de los goles anotados de las ligas europeas NO es igual

Tambien se comparan las medias recortadas con la función t1way

resultado_mean <- t1way (GoalsScored ~ League, data = data)
resultado_mean
Call:
t1way(formula = GoalsScored ~ League, data = data)

Test statistic: F = 0.6291 
Degrees of freedom 1: 4 
Degrees of freedom 2: 27.07 
p-value: 0.64594 

Explanatory measure of effect size: 0.26 
Bootstrap CI: [0.07; 0.42]
p_thresh = 0.05

if (resultado_mean$p.value > p_thresh) {
  cat ("p valor =", resultado_mean$p.value, "\n")
  cat ("Se acepta HO con un nivel de significancia del", p_thresh*100, "%, sugiriendo que la media recortada de los goles anotados de las ligas europeas es igual")
  } else{
    cat ("p valor =", resultado_mean$p.value, "\n")
    cat ("Se rechaza HO con un nivel de significancia del", p_thresh*100, "%, sugiriendo que la media recortalia de los goles anotados de las ligas europeas NO es igual")
  }
p valor = 0.645944 
Se acepta HO con un nivel de significancia del 5 %, sugiriendo que la media recortada de los goles anotados de las ligas europeas es igual

Viendo los resultados de la función t1way se puede observar que no hay diferencias en la cantidad de goles anotados de las ligas europeas. Por lo tanto no haria falta realizar pruebas posthoc, pero para aprender como se usan se aplicarán de todas formas mediante la función lincon de la librería WRS2.

resultado_lincon <- lincon (GoalsScored ~ League, data = data)
resultado_lincon
Call:
lincon(formula = GoalsScored ~ League, data = data)

                          psihat  ci.lower ci.upper p.value
England vs. Italy       -4.25000 -19.40302 10.90302 0.88132
England vs. Spain       -6.50000 -19.13964  6.13964 0.88132
England vs. Germany     -5.08333 -21.58213 11.41546 0.88132
England vs. Netherlands -3.00000 -19.42828 13.42828 0.88132
Italy vs. Spain         -2.25000 -15.72439 11.22439 0.88132
Italy vs. Germany       -0.83333 -17.86787 16.20121 0.88132
Italy vs. Netherlands    1.25000 -15.71778 18.21778 0.88132
Spain vs. Germany        1.41667 -13.67553 16.50886 0.88132
Spain vs. Netherlands    3.50000 -11.50996 18.50996 0.88132
Germany vs. Netherlands  2.08333 -16.01449 20.18116 0.88132
box = ggplot (data = data, aes (x = League, y = GoalsScored) ) +
  geom_boxplot (fill = "#5C7285", color = "#5C7285", alpha = 0.5) +
  theme_bw () +
  labs (x = "Liga", y = "Goles Anotados") +
  ggtitle ("Eurosoccer") +
  theme (
    plot.title = element_text (size = 20, face = "bold", hjust = 0.05),
    axis.text.x = element_text (size = 12),
    axis.text.y = element_text (size = 12),
    axis.title = element_text (size = 14, face = "bold"),
    legend.position = "none"
    )

# Convierte el gráfico a un gráfico interactivo con plotly
box_interactivo <- ggplotly (box)

# Muestra el gráfico interactivo
box_interactivo

Volver al inicio

1.3.2 ANOVA robusto intra-sujetos o de medidas repetidas

El ANOVA robusto de medidas repetidas es una técnica estadística utilizada para analizar datos en los que se realizan mediciones repetidas en los mismos sujetos a lo largo del tiempo o bajo diferentes condiciones, proporciona inferencias válidas incluso cuando los supuestos del ANOVA tradicional no se cumplen.

En el caso de la librería WRS2, tenemos la función rmanova que sirve para analizar datos en los que se realizan mediciones repetidas en los mismos sujetos.

En el caso de que se encuentren diferencias significativas entre grupos se puede usar la función rmmcp para realizar pruebas posthoc y ver entre que grupos existen diferencias.

1.3.2.1 Ejemplo

Usando el dataset (WineTasting) de la librería agricolae, diferentes catadores calan 3 tipos de vino (A, B y C) y le dan una nota en sabor. Sabiendo esto, se quiere calcular si las medias de las notas de los 3 vinos son iguales.

\[\begin{cases} H_0 : \text{Las medias de las notas de los 3 tipos de vino son iguales} \\ H_1 : \text{Al menos la media de nota de 1 de los tipos de vino difiere del resto} \end{cases}\]
library (agricolae)
data (WineTasting)
data = WineTasting

tabla = data %>% datatable (extensions = "Buttons", filter = "top",
                            options = list (
                              scrollY = "200px",
                              pageLength = 20, # Mostrar solo 10 filas por pagina lengthMenu = c(10, 20, 40), # Opciones de selección de cantidad de filas por página
                              ordering = TRUE, # Permitir ordenamiento de columnas
                              dom = 'lBfrtip', # Definir la disposición de los elementos de la tabla
                              buttons = c('copy', 'csv', 'excel', 'pdf', 'print') # Agregar botones de exportacion
                            ),
                            class = 'compact cell-border stripe white-space nowrap' # Estilo de borde de celda y filas alternas resaltadas
                            )
tabla
Taste = data$Taste
Wine = data$Wine
Taster = data$Taster

resultado <- rmanova (y = Taste, groups = Wine, block = Taster)
resultado
Call:
rmanova(y = Taste, groups = Wine, blocks = Taster)

Test statistic: F = 3.2614 
Degrees of freedom 1: 1.61 
Degrees of freedom 2: 20.92 
p-value: 0.06761 
p_thresh = 0.05

if (resultado$p.value > p_thresh) {
  cat ("p valor =", resultado$p.value, "\n")
  cat ("Se acepta HO con un nivel de significancia del", p_thresh*100, "$, sugiriendo que la media de nota de los 3 tipos de vino es igual")
  } else {
    cat ("p valor =", resultado$p.value, "\n")
    cat ("Se rechaza HO con un nivel de significancia del", p_thresh*100, "$, sugiriendo que la media de nota de los 3 tipos de vino es igual")
  }
p valor = 0.06760865 
Se acepta HO con un nivel de significancia del 5 $, sugiriendo que la media de nota de los 3 tipos de vino es igual

Viendo los resultados de la función rmanova se puede observar que no hay diferencias en la media de nota de los tipos de vino. Por lo tanto no haría falta realizar pruebas posthoc, pero para aprender como se usan se aplicarán de todas formas mediante la función rmmcp.

resultado_posthoc <- rmmcp(y = Taste, groups = Wine, block = Taster)
resultado_posthoc
Call:
rmmcp(y = Taste, groups = Wine, blocks = Taster)

                   psihat ci.lower ci.upper p.value p.crit   sig
Wine A vs. Wine B 0.02143 -0.02164  0.06449 0.19500 0.0500 FALSE
Wine A vs. Wine C 0.11429  0.02148  0.20710 0.00492 0.0169  TRUE
Wine B vs. Wine C 0.08214  0.00891  0.15538 0.00878 0.0250  TRUE
x <- resultado_posthoc$comp
valores_p <- x[, 6]

comparaciones <- c("Wine A vs Wine B", "Wine A vs Wine C", "Wine B vs Wine C")

p_thresh <- 0.05
for(j in 1:length (valores_p) ) {
  if(valores_p[j] < p_thresh) {
    cat ("Valor p = ", valores_p[j], "\n")
    cat ("Se rechaza HO con un nivel de significancia del", p_thresh*100, "% Para la comparacion", comparaciones[j], "sugiriendo que existen diferencias entre la nota de estos vinos \n\n")
    } else{
      cat ("Valor p = ", valores_p[j], "\n")
      cat ("Se acepta HO con un nivel de significancia del", p_thresh*100, "$ Para la comparacion", comparaciones [j], "sugiriendo que NO existen diferencias entre la nota de estos vinos \n\n")
    }
}
Valor p =  0.1950045 
Se acepta HO con un nivel de significancia del 5 $ Para la comparacion Wine A vs Wine B sugiriendo que NO existen diferencias entre la nota de estos vinos 

Valor p =  0.004915566 
Se rechaza HO con un nivel de significancia del 5 % Para la comparacion Wine A vs Wine C sugiriendo que existen diferencias entre la nota de estos vinos 

Valor p =  0.008777396 
Se rechaza HO con un nivel de significancia del 5 % Para la comparacion Wine B vs Wine C sugiriendo que existen diferencias entre la nota de estos vinos 
# Calcular un valor de posición 'y' para cada anotación
comparaciones_significativas <- data.frame (
  grupo1 = c("Wine A", "Wine B"),
  grupo2 = c("Wine C", "Wine C"),
  p_value = c(valores_p[2], valores_p[3] ) )

# Agregar una columna para las anotaciones de significancia basada en los p-valores
comparaciones_significativas$annotation <- ifelse(
  comparaciones_significativas$p_value < 0.001, ' *** ',
  ifelse (
    comparaciones_significativas$p_value < 0.01, ' ** ',
    ifelse(
      comparaciones_significativas$p_value < 0.05, '*', 'ns'
      )
    )
  )

max_valor = max (data$Taste, na.rm = TRUE)
espacio_entre_anotaciones = max_valor * 0.05 # ajusta este valor según sea necesario

# Agregar las posiciones 'y' al dataframe
comparaciones_significativas$y_position <- seq(from = max_valor + espacio_entre_anotaciones/2,

by = espacio_entre_anotaciones,
length.out = nrow(comparaciones_significativas))

# Creando el gráfico base de cajas
p <- ggplot (data, aes (x = Wine, y = Taste) ) + 
  geom_boxplot (fill = "#5C7285", color = "#5C7285", alpha = 0.5) + 
  theme_bw () +
  labs (x = "Tipo de vino", y = "Nota de los catadores") +
  ggtitle ("WineTasting") +
  theme(
    plot.title = element_text (size = 20, face = "bold", hjust = 0.05),
    axis.text.x = element_text (size = 12),
    axis.text.y = element_text (size = 12),
    axis.title = element_text (size = 14, face = "bold"),
    legend.position = "none")

# Añadiendo las anotaciones de significancia usando geom signif
p <- p + geom_signif(
  data = comparaciones_significativas,
  aes (xmin = grupo1, xmax = grupo2, annotations = annotation, y_position = y_position),
  manual = TRUE,
  )

# Ajustar los limites del eje y para acomodar las anotaciones
p <- p + ylim(4.5, max(comparaciones_significativas$y_position) *1.01)

# Imprimir el gráfico
p

Volver al inicio