¡Perfecto, Justo! Con este cuaderno cerramos con broche de oro la primera gran familia de la función ea1.

La Prueba de Friedman es la herramienta de salvación cuando un experimento fue rigurosamente planeado con bloques (para controlar un gradiente ambiental, lotes de materia prima, etc.), pero al momento de recolectar los datos, estos resultan tener una distribución asimétrica severa, valores atípicos que no se pueden descartar, o son datos medidos en escalas ordinales (como calificaciones de cata o evaluaciones de calidad visual).

Aquí tienes la estructura pedagógica para que tus estudiantes aprendan a sortear estos problemas en un escenario con bloques.


📘 Cuaderno 10: Prueba de Friedman (Alternativa no paramétrica para DBCA)

a) Introducción Teórica a la Prueba de Friedman

La prueba de Friedman es el equivalente no paramétrico del Diseño en Bloques Completamente al Azar (DBCA). Se utiliza cuando los datos obtenidos en un experimento con bloques violan los supuestos de normalidad y homogeneidad de varianzas necesarios para un ANOVA clásico.

El concepto central de Friedman es que los rangos se asignan de forma independiente dentro de cada bloque. Al no mezclar los rangos entre diferentes bloques, se mantiene intacto el principio de “control local” del error experimental, neutralizando el efecto del bloque antes de comparar los tratamientos.

El Estadístico de Prueba (\(\chi_r^2\)): La fórmula para calcular el estadístico de Friedman (que se aproxima a una distribución Chi-cuadrado) es:

\[\chi_r^2 = \frac{12}{bk(k+1)} \sum_{i=1}^{k} R_i^2 - 3b(k+1)\]

Donde: * \(b\): Es el número total de bloques. * \(k\): Es el número total de tratamientos. * \(R_i\): Es la suma de los rangos para el \(i\)-ésimo tratamiento.

(Nota: Si existen empates significativos en los datos, se debe aplicar un factor de corrección a esta fórmula. El software estadístico lo hace automáticamente).


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

Para comprender cómo Friedman aísla el efecto del bloque mediante rangos, guía a tus alumnos con estos pasos:

  1. Construir la Matriz: Dibuja una tabla donde las filas sean los Bloques (\(b\)) y las columnas sean los Tratamientos (\(k\)). Coloca los datos brutos en las celdas correspondientes.
  2. Asignar Rangos por Fila (Bloque): ¡Esta es la clave! Toma el Bloque 1 y asigna rangos (1, 2, 3…) solo a los datos de ese bloque, del menor al mayor. Luego pasa al Bloque 2 y vuelve a empezar la asignación de rangos desde 1. Haz esto para todos los bloques.
    • (Si un bloque era muy fértil y todos sus datos eran altos, al usar rangos relativos internos, eliminamos matemáticamente esa “ventaja” de fertilidad).
  3. Sumar los Rangos por Tratamiento (\(R_i\)): Suma los rangos de cada columna (Tratamiento) hacia abajo. Si la hipótesis nula es cierta (no hay diferencias entre tratamientos), las sumas de los rangos \(R_i\) deberían ser muy similares entre sí.
  4. Calcular el Estadístico \(\chi_r^2\): Introduce los valores de \(b\), \(k\) y los \(R_i\) obtenidos en la fórmula matemática.
  5. Conclusión: Compara el valor calculado de \(\chi_r^2\) con el valor crítico de la tabla Chi-cuadrado para \(k-1\) grados de libertad. Si el calculado es mayor, concluye que existen diferencias significativas en las medianas de los tratamientos.

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

Simularemos un escenario agroindustrial (ej. calificación de textura de 3 formulaciones de un alimento, evaluadas por 5 jueces distintos que actúan como bloques). Los datos ordinales o con sesgos requieren visualizaciones específicas.

library(easyanova)

# Simulación de un dataset para Friedman
# Col 1: Tratamiento, Col 2: Bloque (Juez), Col 3: Respuesta (Escala no paramétrica o con atípicos)
set.seed(42)
datos_friedman <- data.frame(
  Tratamiento = rep(c("Formulacion_A", "Formulacion_B", "Formulacion_C"), times = 5),
  Bloque = rep(c("Juez1", "Juez2", "Juez3", "Juez4", "Juez5"), each = 3),
  Respuesta = c(5, 7, 2,   # Juez 1 (Baja calificación general, atípico en B)
                18, 25, 12, # Juez 2 (Alta calificación general)
                6, 9, 4,   # Juez 3
                20, 30, 15, # Juez 4
                8, 11, 5)  # Juez 5
)

# EDA 1: Gráfico de perfil o interacción para ver el comportamiento intra-bloque
# install.packages("ggplot2")
library(ggplot2)

ggplot(datos_friedman, aes(x = Tratamiento, y = Respuesta, group = Bloque, color = Bloque)) +
  geom_line(size = 1) +
  geom_point(size = 4) +
  labs(title = "Comportamiento de los Tratamientos por Bloque",
       subtitle = "Noten cómo el orden (rango) de A, B y C se mantiene, aunque los jueces califiquen en escalas muy distintas",
       y = "Respuesta Observada") +
  theme_minimal()

# EDA 2: Prueba de normalidad de los residuos de un modelo lineal (para justificar Friedman)
modelo_lineal <- lm(Respuesta ~ Tratamiento + Bloque, data = datos_friedman)
shapiro.test(residuals(modelo_lineal)) # Probablemente arroje p < 0.05

Propósito pedagógico: El gráfico de líneas es fundamental. Hazles notar a los estudiantes que, aunque las líneas suben y bajan radicalmente dependiendo del juez (efecto de bloque gigante), dentro de cada línea, la ‘Formulación B’ casi siempre es el punto más alto. Friedman detectará ese patrón consistente de rangos independientemente de los valores absolutos.


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

La función ea1 simplifica enormemente el proceso ejecutando Friedman con design = 15.

# Ejecutar Prueba de Friedman (Alternativa no paramétrica para DBCA) -> design = 15
# El orden estricto de las columnas debe ser: Col 1 = Tratamiento, Col 2 = Bloque, Col 3 = Respuesta
resultado_friedman <- ea1(datos_friedman, design = 15)

# Imprimir los resultados. El paquete se encarga del ranking interno.
print(resultado_friedman)

e) Prompts Sugeridos para tus Estudiantes

Guía la capacidad crítica de los estudiantes indicándoles que te hagan estas preguntas sobre su output:

  1. “Hola. Ejecuté la prueba de Friedman para mis datos de campo estructurados en bloques. Si mi valor p es menor a 0.05, ¿qué debo reportar exactamente: que las ‘medias’ de mis tratamientos son diferentes o que las ‘medianas/distribuciones’ son diferentes?”
  2. “En clase aprendimos Kruskal-Wallis y ahora Friedman. Si tengo un experimento estructurado en bloques pero decido ignorarlos y correr un Kruskal-Wallis, ¿qué error metodológico estoy cometiendo al asignar los rangos a los datos?”
  3. “Después de que la prueba de Friedman me indica que hay diferencias significativas generales, ¿qué tipo de prueba post-hoc me sugiere el software (ej. Wilcoxon, Nemenyi) para saber específicamente qué tratamiento superó al otro?”

f) Plantillas Alternativas: Python y Julia

En Python (Usando scipy.stats): En Python, scipy requiere que los datos estén agrupados de una manera específica (cada tratamiento como una lista paralela, donde el índice representa el bloque).

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

# Dataset estructurado como matriz (Filas = Bloques, Columnas = Tratamientos)
# Bloques: Juez1 a Juez5
form_a = [5, 18, 6, 20, 8]
form_b = [7, 25, 9, 30, 11]
form_c = [2, 12, 4, 15, 5]

# Creación de DataFrame para visualización
df = pd.DataFrame({
    'Formulacion_A': form_a,
    'Formulacion_B': form_b,
    'Formulacion_C': form_c
})

# EDA: Boxplots pareados
sns.boxplot(data=df)
plt.title('Distribución de Respuestas por Tratamiento')
plt.show()

# Ejecución de la prueba de Friedman
estadistico_friedman, p_valor = friedmanchisquare(form_a, form_b, form_c)

print("\n--- Resultados de la Prueba de Friedman ---")
print(f"Estadístico Chi-cuadrado de Friedman: {estadistico_friedman:.4f}")
print(f"Valor p: {p_valor:.4f}")

En Julia (Usando HypothesisTests): En Julia, pasamos una matriz bidimensional donde las columnas son los tratamientos y las filas son los bloques.

using HypothesisTests

# Matriz de datos: Filas (Bloques/Jueces), Columnas (Tratamientos)
# Trats: Form_A, Form_B, Form_C
matriz_datos = [
    5.0   7.0   2.0;  # Bloque 1
    18.0  25.0  12.0; # Bloque 2
    6.0   9.0   4.0;  # Bloque 3
    20.0  30.0  15.0; # Bloque 4
    8.0   11.0  5.0   # Bloque 5
]

# Ejecutar la prueba de Friedman
prueba_fr = FriedmanTest(matriz_datos)

println("--- Prueba de Friedman en Julia ---")
println(prueba_fr)

¡Misión cumplida con la función ea1! Hemos cubierto todos los diseños simples y no paramétricos.

A partir de aquí, el plan semestral daría el gran salto hacia la función ea2, entrando al territorio de los Diseños Factoriales (cuando cruzamos dos o más factores al mismo tiempo, como Variedad de Semilla \(\times\) Dosis de Fertilizante).