1. Introducción, objetivo e hipótesis

Se investiga si la concentración de croscarmelosa sódica modifica el tiempo de desintegración de comprimidos de paracetamol de 500 mg. Se comparan cuatro concentraciones (1 %, 2 %, 3 % y 4 %), con tres lotes experimentales independientes por concentración. La asignación de concentraciones a las unidades experimentales se considera aleatoria. Las demás condiciones de fabricación se mantienen controladas.

Hipótesis del ANOVA: H₀: las cuatro medias poblacionales son iguales; H₁: al menos una difiere. Nivel de significancia: α = 0.05.

Importante: todos los datos son simulados. El tiempo menor no define por sí solo la formulación óptima: deben evaluarse especificaciones, disolución, friabilidad y otros atributos pertinentes.

2. Datos experimentales

datos <- data.frame(
  Concentracion = factor(rep(c('1 %','2 %','3 %','4 %'), each=3), levels=c('1 %','2 %','3 %','4 %')),
  Lote_independiente = rep(paste0('Replica ',1:3), times=4),
  Tiempo_min = c(12.1,11.6,12.5, 9.8,9.1,9.5, 7.6,7.0,7.4, 5.7,5.2,5.5)
)
knitr::kable(datos, digits=2, caption='Datos ficticios: una respuesta por lote experimental independiente')
Datos ficticios: una respuesta por lote experimental independiente
Concentracion Lote_independiente Tiempo_min
1 % Replica 1 12.1
1 % Replica 2 11.6
1 % Replica 3 12.5
2 % Replica 1 9.8
2 % Replica 2 9.1
2 % Replica 3 9.5
3 % Replica 1 7.6
3 % Replica 2 7.0
3 % Replica 3 7.4
4 % Replica 1 5.7
4 % Replica 2 5.2
4 % Replica 3 5.5

3. Estadística descriptiva

descriptivos <- datos %>% group_by(Concentracion) %>% summarise(
  n=n(), Media=mean(Tiempo_min), Mediana=median(Tiempo_min),
  DE=sd(Tiempo_min), Varianza=var(Tiempo_min),
  Minimo=min(Tiempo_min), Maximo=max(Tiempo_min),
  CV_porcentaje=100*sd(Tiempo_min)/mean(Tiempo_min),
  EE=sd(Tiempo_min)/sqrt(n()), .groups='drop'
)
knitr::kable(descriptivos, digits=3, caption='Descriptivos por concentración')
Descriptivos por concentración
Concentracion n Media Mediana DE Varianza Minimo Maximo CV_porcentaje EE
1 % 3 12.067 12.1 0.451 0.203 11.6 12.5 3.737 0.260
2 % 3 9.467 9.5 0.351 0.123 9.1 9.8 3.710 0.203
3 % 3 7.333 7.4 0.306 0.093 7.0 7.6 4.166 0.176
4 % 3 5.467 5.5 0.252 0.063 5.2 5.7 4.604 0.145

El CV expresa la variabilidad relativa; la DE mide dispersión en minutos; el EE cuantifica la precisión de la media muestral.

4. Visualizaciones a color

4.1. Diagrama de cajas con cada observación

ggplot(datos, aes(Concentracion, Tiempo_min, fill=Concentracion)) +
  geom_boxplot(width=.55, alpha=.48, outlier.shape=NA) +
  geom_jitter(width=.09, height=0, size=3.8, shape=21, color='#1B2631', alpha=.95) +
  scale_fill_manual(values=colores) +
  labs(title='Distribución del tiempo de desintegración', subtitle='Cada punto es un lote experimental independiente', x='Croscarmelosa sódica', y='Tiempo de desintegración (min)') +
  tema + theme(legend.position='none')

4.2. Medias y desviación estándar

ggplot(descriptivos, aes(Concentracion, Media, fill=Concentracion)) +
  geom_col(width=.65, alpha=.85) +
  geom_errorbar(aes(ymin=pmax(0,Media-DE), ymax=Media+DE), width=.18, linewidth=.85) +
  geom_text(aes(label=sprintf('%.2f min',Media)), vjust=-.8, fontface='bold', size=4.5) +
  scale_fill_manual(values=colores) +
  scale_y_continuous(limits=c(0,max(descriptivos$Media+descriptivos$DE)+2),expand=c(0,0)) +
  labs(title='Tiempo medio de desintegración ± DE', x='Concentración de desintegrante', y='Tiempo medio (min)') +
  tema + theme(legend.position='none')

4.3. Tendencia de las medias

ggplot(descriptivos, aes(Concentracion, Media, group=1)) +
  geom_line(color='#2C3E50',linewidth=1.1) +
  geom_point(aes(color=Concentracion),size=4) +
  geom_text(aes(label=sprintf('%.2f',Media)), vjust=-1.0,fontface='bold') +
  scale_color_manual(values=colores) +
  labs(title='Tendencia descriptiva del tiempo medio', x='Concentración de croscarmelosa sódica', y='Tiempo medio (min)') +
  tema + theme(legend.position='none')

5. ANOVA de un factor (DCA)

modelo <- aov(Tiempo_min ~ Concentracion, data=datos)
tabla_anova <- as.data.frame(summary(modelo)[[1]])
tabla_anova$Fuente <- trimws(rownames(tabla_anova))
tabla_anova <- tabla_anova[,c('Fuente','Df','Sum Sq','Mean Sq','F value','Pr(>F)')]
names(tabla_anova) <- c('Fuente','GL','SC','CM','F','p')
knitr::kable(tabla_anova, digits=5, caption='Tabla ANOVA del DCA')
Tabla ANOVA del DCA
Fuente GL SC CM F p
Concentracion Concentracion 3 72.57000 24.19000 200.1931 0
Residuals Residuals 8 0.96667 0.12083 NA NA
p_anova <- tabla_anova$p[match('Concentracion', tabla_anova$Fuente)]
cat('**Interpretación:** p =', formato_p(p_anova),'. ',
    if(p_anova<alpha) 'Se rechaza H₀: al menos una media de desintegración difiere.' else 'No se rechaza H₀: no se detectan diferencias suficientes entre medias.', '\n')
## **Interpretación:** p = < 0.0001 .  Se rechaza H₀: al menos una media de desintegración difiere.

5.1. Tamaño del efecto: eta cuadrado

sc_factor <- tabla_anova$SC[match('Concentracion',tabla_anova$Fuente)]
sc_error <- tabla_anova$SC[match('Residuals',tabla_anova$Fuente)]
eta2 <- sc_factor/(sc_factor+sc_error)
knitr::kable(data.frame(Medida='Eta cuadrado (η²)',Valor=eta2),digits=4)
Medida Valor
Eta cuadrado (η²) 0.9869

Interpretación: η² describe la proporción de variabilidad total de la respuesta asociada al factor en este conjunto de datos; no equivale a una prueba de significancia ni garantiza relevancia clínica o farmacotécnica.

6. Evaluación de supuestos

6.1. Normalidad de los residuos: Shapiro-Wilk

H₀: los errores tienen distribución normal. H₁: no tienen distribución normal.

residuos <- residuals(modelo)
normalidad <- shapiro.test(residuos)
knitr::kable(data.frame(Prueba='Shapiro-Wilk',W=unname(normalidad$statistic),p=normalidad$p.value),digits=5)
Prueba W p
Shapiro-Wilk 0.93113 0.39219
cat('**Interpretación:** p =',formato_p(normalidad$p.value),'. ',
    if(normalidad$p.value<alpha) 'Se rechaza H₀: existe evidencia contra la normalidad de los residuos.' else 'No se rechaza H₀: no hay evidencia suficiente contra la normalidad de los residuos.', '\n')
## **Interpretación:** p = 0.3922 .  No se rechaza H₀: no hay evidencia suficiente contra la normalidad de los residuos.
ggplot(data.frame(Residuos=residuos),aes(sample=Residuos)) +
  stat_qq(color='#2471A3',size=3) + stat_qq_line(color='#E74C3C',linewidth=1) +
  labs(title='Gráfico Q-Q de los residuos',x='Cuantiles teóricos',y='Cuantiles observados') + tema

6.2. Homogeneidad de varianzas: Levene (mediana)

H₀: las varianzas son iguales. H₁: al menos una varianza difiere.

lev <- car::leveneTest(Tiempo_min ~ Concentracion,data=datos,center=median)
knitr::kable(as.data.frame(lev),digits=5,caption='Prueba de Levene')
Prueba de Levene
Df F value Pr(>F)
group 3 0.22013 0.87977
8 NA NA
p_levene <- as.numeric(lev[1,'Pr(>F)'])
cat('**Interpretación:** p =',formato_p(p_levene),'. ',
    if(p_levene<alpha) 'Se rechaza H₀: evidencia de varianzas diferentes.' else 'No se rechaza H₀: no se detectan diferencias suficientes entre varianzas.', '\n')
## **Interpretación:** p = 0.8798 .  No se rechaza H₀: no se detectan diferencias suficientes entre varianzas.

6.3. Residuos frente a valores ajustados

diagnostico <- data.frame(Ajustados=fitted(modelo),Residuos=residuos,Concentracion=datos$Concentracion)
ggplot(diagnostico,aes(Ajustados,Residuos,color=Concentracion)) +
  geom_hline(yintercept=0,linetype='dashed',color='#C0392B') +
  geom_point(size=3.8,alpha=.9) + scale_color_manual(values=colores) +
  labs(title='Residuos frente a valores ajustados',x='Tiempo ajustado (min)',y='Residuo (min)',color='Concentración') + tema

6.4. Independencia y aleatorización

La independencia no se demuestra con Shapiro-Wilk ni con Levene. Depende de que los tres lotes por tratamiento sean unidades experimentales independientes, que la asignación haya sido aleatoria y que no exista pseudorreplicación. El código no puede verificar cómo se fabricaron los lotes.

7. Comparaciones múltiples: Tukey

tukey <- TukeyHSD(modelo,which='Concentracion')
tabla_tukey <- data.frame(Comparacion=rownames(tukey$Concentracion),tukey$Concentracion,row.names=NULL,check.names=FALSE)
knitr::kable(tabla_tukey,digits=5,caption='Comparaciones de Tukey (IC 95 % y p ajustado)')
Comparaciones de Tukey (IC 95 % y p ajustado)
Comparacion diff lwr upr p adj
2 %-1 % -2.60000 -3.50890 -1.69110 0.00008
3 %-1 % -4.73333 -5.64223 -3.82443 0.00000
4 %-1 % -6.60000 -7.50890 -5.69110 0.00000
3 %-2 % -2.13333 -3.04223 -1.22443 0.00031
4 %-2 % -4.00000 -4.90890 -3.09110 0.00000
4 %-3 % -1.86667 -2.77557 -0.95777 0.00079
plot(tukey,las=1,col='#7D3C98')

Interpretación: una comparación es significativa cuando el p ajustado es menor que 0.05 o el intervalo de confianza de la diferencia no contiene cero. Tukey se interpreta bajo los supuestos del modelo ANOVA.

8. Alternativa no paramétrica: Kruskal-Wallis

kw <- kruskal.test(Tiempo_min ~ Concentracion,data=datos)
knitr::kable(data.frame(Prueba='Kruskal-Wallis',Estadistico=unname(kw$statistic),GL=unname(kw$parameter),p=kw$p.value),digits=5)
Prueba Estadistico GL p
Kruskal-Wallis 10.38462 3 0.01556
cat('**Interpretación:** p =',formato_p(kw$p.value),'. ',
    if(kw$p.value<alpha) 'Se rechaza H₀: hay evidencia de diferencias en la distribución de las respuestas entre concentraciones.' else 'No se rechaza H₀: no se detectan diferencias suficientes entre concentraciones.', '\n')
## **Interpretación:** p = 0.0156 .  Se rechaza H₀: hay evidencia de diferencias en la distribución de las respuestas entre concentraciones.

Si procede una comparación post hoc no paramétrica, pueden explorarse pruebas de Wilcoxon por pares con ajuste de Holm (exploratorias, dada la muestra pequeña):

posthoc_kw <- pairwise.wilcox.test(datos$Tiempo_min,datos$Concentracion,p.adjust.method='holm',exact=FALSE)
knitr::kable(as.data.frame(as.table(posthoc_kw$p.value)),digits=5,caption='Wilcoxon por pares: p ajustados por Holm (NA = comparación no definida en esa mitad de la matriz)')
Wilcoxon por pares: p ajustados por Holm (NA = comparación no definida en esa mitad de la matriz)
Var1 Var2 Freq
2 % 1 % 0.48513
3 % 1 % 0.48513
4 % 1 % 0.48513
2 % 2 % NA
3 % 2 % 0.48513
4 % 2 % 0.48513
2 % 3 % NA
3 % 3 % NA
4 % 3 % 0.48513

9. Resumen automático

resumen <- data.frame(
  Prueba=c('ANOVA: concentración','Shapiro-Wilk: residuos','Levene: igualdad de varianzas','Kruskal-Wallis'),
  p=c(p_anova,normalidad$p.value,p_levene,kw$p.value)
)
resumen$Decision <- ifelse(resumen$p<alpha,'Rechazar H0','No rechazar H0')
knitr::kable(resumen,digits=5,caption='Resumen de contrastes (α = 0.05)')
Resumen de contrastes (α = 0.05)
Prueba p Decision
ANOVA: concentración 0.00000 Rechazar H0
Shapiro-Wilk: residuos 0.39219 No rechazar H0
Levene: igualdad de varianzas 0.87977 No rechazar H0
Kruskal-Wallis 0.01556 Rechazar H0

10. Conclusiones e interpretación farmacéutica

menor <- descriptivos[which.min(descriptivos$Media),]
mayor <- descriptivos[which.max(descriptivos$Media),]
cat('- La concentración con menor tiempo medio observado fue **',as.character(menor$Concentracion),'** (',sprintf('%.2f',menor$Media),' min).\n',sep='')
cat('- La concentración con mayor tiempo medio observado fue **',as.character(mayor$Concentracion),'** (',sprintf('%.2f',mayor$Media),' min).\n',sep='')
cat('- El ANOVA ',if(p_anova<alpha) 'detectó' else 'no detectó',' diferencias estadísticamente significativas entre las medias (p ',formato_p(p_anova),').\n',sep='')
cat('- Shapiro-Wilk ',if(normalidad$p.value<alpha) 'cuestiona' else 'no cuestiona estadísticamente',' la normalidad de los residuos al nivel α = 0.05.\n',sep='')
cat('- Levene ',if(p_levene<alpha) 'detectó diferencias' else 'no detectó diferencias estadísticamente significativas',' entre las varianzas por concentración.\n',sep='')
cat('- Kruskal-Wallis ',if(kw$p.value<alpha) 'detectó' else 'no detectó',' diferencias estadísticamente significativas entre grupos.\n',sep='')

Alcance: estos datos son ficticios y no constituyen evidencia de desempeño real. Una formulación no debe seleccionarse únicamente por reducir el tiempo de desintegración: deben considerarse criterios de aceptación definidos para el producto, disolución, friabilidad y otros atributos de calidad. Para un estudio real se requiere documentar la aleatorización y la independencia de los lotes experimentales.