Dar el salto a la estadística no paramétrica es vital para tus estudiantes. En el mundo real de la Ingeniería Agrícola y Agroindustrial, los datos no siempre son “perfectos”. A veces hay valores atípicos extremos (como una planta que creció el doble que las demás por una anomalía) o los datos están muy sesgados (como conteos de insectos o bacterias), lo que destruye los supuestos de normalidad y homogeneidad de varianzas del ANOVA tradicional.

Aquí tienes el desarrollo para enseñarles su primera herramienta de “rescate” estadístico.


📘 Cuaderno 9: Prueba de Kruskal-Wallis (Alternativa no paramétrica para DCA)

a) Introducción Teórica a la Prueba de Kruskal-Wallis

La prueba de Kruskal-Wallis es el equivalente no paramétrico del Diseño Completamente al Azar (DCA). Cuando los datos no cumplen con los supuestos matemáticos para un ANOVA (normalidad de los residuos y varianzas iguales entre grupos), no podemos confiar en las medias para tomar decisiones.

En lugar de trabajar con los valores reales medidos (ej. kilogramos, centímetros), Kruskal-Wallis ordena todos los datos de menor a mayor y les asigna un rango (una posición). Luego, compara si la suma de esos rangos difiere significativamente entre los tratamientos. Al hacer esto, la prueba evalúa si las medianas (o las distribuciones en general) son diferentes, volviéndose altamente resistente a los valores atípicos.

El Estadístico de Prueba (\(H\)): La fórmula básica para calcular el estadístico de Kruskal-Wallis es:

\[H = \frac{12}{N(N+1)} \sum_{i=1}^{t} \frac{R_i^2}{n_i} - 3(N+1)\]

Donde: * \(N\): Es el número total de observaciones en todo el experimento. * \(t\): Es el número de tratamientos. * \(R_i\): Es la suma de los rangos para el \(i\)-ésimo tratamiento. * \(n_i\): Es el número de repeticiones (observaciones) en el \(i\)-ésimo tratamiento.

(Nota: Si el valor de \(H\) calculado es mayor que el valor crítico de la tabla de distribución Chi-cuadrado (\(\chi^2\)) con \(t-1\) grados de libertad, se rechaza la hipótesis nula y se concluye que al menos un tratamiento es diferente).


b) Miniguía: Solución Manual (Papel y Lápiz)

Para que los alumnos comprendan el concepto de “rango”, pídeles que resuelvan un ejercicio pequeño (ej. 3 tratamientos con 4 repeticiones cada uno) siguiendo estos pasos:

  1. Agrupar y Ordenar: Olvida temporalmente a qué tratamiento pertenece cada dato. Coloca todos los \(N\) datos en una sola lista y ordénalos del valor más pequeño al más grande.
  2. Asignar Rangos: Al valor más pequeño asígnale el rango 1, al siguiente el 2, y así sucesivamente hasta \(N\).
    • Regla de los empates: Si dos o más datos tienen exactamente el mismo valor, se les asigna el promedio de los rangos que estarían ocupando. (Ej: Si los valores en la posición 3 y 4 son idénticos, ambos reciben el rango 3.5).
  3. Reagrupar por Tratamiento: Devuelve cada rango a su tratamiento original.
  4. Sumar los Rangos (\(R_i\)): Suma los rangos dentro de cada tratamiento. (Comprobación rápida: La suma de todos los rangos del experimento debe ser igual a \(\frac{N(N+1)}{2}\)).
  5. Calcular \(H\): Aplica la fórmula matemática descrita arriba.
  6. Conclusión: Compara el valor de \(H\) con el valor de \(\chi^2\) (Chi-cuadrado) para \(t-1\) grados de libertad y un alfa de 0.05.

c) Exploración de Datos (EDA) en R

Aquí el objetivo del EDA no es solo ver diferencias, sino diagnosticar por qué no usamos el ANOVA clásico. Usaremos una estructura de datos de dos columnas (Tratamiento y Respuesta).

library(easyanova)

# Para este ejemplo, simularemos un dataset donde claramente fallan los supuestos
# (Ej: Datos muy sesgados o con valores atípicos fuertes en agroindustria)
set.seed(123)
datos_kw <- data.frame(
  Tratamiento = rep(c("T1", "T2", "T3"), each = 10),
  Respuesta = c(rexp(10, rate=0.5), rexp(10, rate=0.5), rexp(10, rate=0.1)) # Distribución exponencial (no normal)
)

# Añadimos un valor atípico extremo simulando un error de medición
datos_kw$Respuesta[1] <- 45.0 

# EDA 1: Boxplot para evidenciar asimetría y valores atípicos
boxplot(Respuesta ~ Tratamiento, data = datos_kw, 
        col = c("lightgreen", "lightblue", "salmon"),
        main = "Respuesta por Tratamiento (Datos No Normales)",
        ylab = "Respuesta (con asimetría y atípicos)")

# EDA 2: Prueba de Normalidad de Shapiro-Wilk para toda la respuesta
# Esto justifica cuantitativamente el uso de Kruskal-Wallis
shapiro.test(datos_kw$Respuesta)

Propósito pedagógico: Pregúntales a los estudiantes qué observan en el boxplot. El valor atípico (el punto solitario muy arriba) y las cajas aplastadas hacia abajo indican asimetría. Si el p-value de la prueba de Shapiro-Wilk es menor a 0.05, los datos no son normales, y Kruskal-Wallis entra a salvar el análisis.


d) Plantilla de Código R: Solución con easyanova

Ejecutar esta alternativa en el paquete es tan sencillo como cambiar el diseño a 14. El paquete internamente hace la transformación a rangos y arroja el resultado.

# Ejecutar Kruskal-Wallis (Alternativa no paramétrica para DCA) -> design = 14
# Orden requerido: Col 1 = Tratamiento, Col 2 = Respuesta
resultado_kw <- ea1(datos_kw, design = 14)

# Imprimir los resultados. easyanova mostrará la prueba basada en rangos.
print(resultado_kw)

e) Prompts Sugeridos para tus Estudiantes

Motiva la interacción analítica con estos prompts:

  1. “Hola. Acabo de correr la función ea1 con el diseño 14 para unos datos de germinación de semillas. ¿Qué me dice el valor p de la prueba de Kruskal-Wallis sobre las medianas de mis tratamientos?”
  2. “En el EDA vimos un valor atípico enorme en el Tratamiento 1. Si hubiéramos usado el ANOVA clásico (diseño 1), ¿cómo habría afectado ese valor extremo al promedio y a la conclusión final? ¿Por qué Kruskal-Wallis ignoró la magnitud de ese valor?”
  3. “En los resultados del software, ¿qué prueba ‘post-hoc’ (de comparación múltiple) se utilizó para separar los grupos ahora que no podemos usar Tukey ni Scott-Knott basados en medias?”

f) Plantillas Alternativas: Python y Julia

En Python (Usando scipy.stats y seaborn): Python tiene librerías muy eficientes para estadística no paramétrica. scipy.stats realiza la prueba central y podemos usar scikit-posthocs si se desea hacer la separación de grupos.

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats

# Dataset simulado (Tratamiento y Respuesta)
data = {
    'Tratamiento': ['T1']*5 + ['T2']*5 + ['T3']*5,
    'Respuesta': [2, 3, 2.5, 3.1, 40,   # T1 tiene un atípico fuerte (40)
                  5, 6, 5.5, 6.2, 5.8, 
                  10, 12, 11, 10.5, 11.2]
}
df = pd.DataFrame(data)

# EDA: Gráfico de enjambre (Swarmplot) para ver cada dato individual
sns.swarmplot(x='Tratamiento', y='Respuesta', data=df, size=8)
plt.title('Dispersión de Datos (Notar el valor atípico en T1)')
plt.show()

# Separar los datos por grupos para la función de scipy
grupo1 = df[df['Tratamiento'] == 'T1']['Respuesta']
grupo2 = df[df['Tratamiento'] == 'T2']['Respuesta']
grupo3 = df[df['Tratamiento'] == 'T3']['Respuesta']

# Ejecutar Kruskal-Wallis
estadistico_H, p_valor = stats.kruskal(grupo1, grupo2, grupo3)

print("\n--- Resultados Kruskal-Wallis ---")
print(f"Estadístico H: {estadistico_H:.4f}")
print(f"Valor p: {p_valor:.4f}")

En Julia (Usando DataFrames y HypothesisTests):

using DataFrames, HypothesisTests

# DataFrame simulado
df = DataFrame(
    Tratamiento = repeat(["T1", "T2", "T3"], inner=5),
    Respuesta = [2.0, 3.0, 2.5, 3.1, 40.0, 
                 5.0, 6.0, 5.5, 6.2, 5.8, 
                 10.0, 12.0, 11.0, 10.5, 11.2]
)

# Para usar Kruskal-Wallis en Julia, se pasan los arreglos de cada grupo
t1 = df[df.Tratamiento .== "T1", :Respuesta]
t2 = df[df.Tratamiento .== "T2", :Respuesta]
t3 = df[df.Tratamiento .== "T3", :Respuesta]

# Ejecutar la prueba
prueba_kw = KruskalWallisTest(t1, t2, t3)

println("--- Prueba de Kruskal-Wallis en Julia ---")
println(prueba_kw)

Con esto, los estudiantes ya tienen cómo defenderse de datos problemáticos en un escenario completamente al azar. ¿Te gustaría que pasemos a la 15. Prueba de suma de rangos de Friedman (Alternativa no paramétrica para DBCA) para cerrar el ciclo de la función ea1?