library(psych)
library(knitr)
library(kableExtra)
library(ggplot2)
library(dplyr)
library(car)
library(agricolae)
library(gridExtra)
cv <- function(x) (sd(x) / mean(x)) * 100
Este informe reúne tres estudios independientes (suelos y biomasa vegetal, fisiología de moluscos y biodiversidad de anfibios) con el fin de aplicar análisis exploratorio, ANOVA y pruebas post-ANOVA sobre datos biológicos y ambientales. En cada punto se sigue la misma lógica: describir las variables, evaluar diferencias entre grupos verificando los supuestos del modelo, y confirmar con pruebas post-hoc cuáles grupos difieren entre sí, interpretando cada resultado en su contexto.
Para estudiar la relación entre ciertas características del suelo y la producción de biomasa (g) de una planta forrajera natural, se recolectaron 45 muestras en diferentes ambientes. En cada una se registró la biomasa producida (variable respuesta) y cuatro covariables del suelo: pH, salinidad, zinc y potasio.
45Muestras
4Covariables del suelo
1Variable respuesta (Biomasa)
load("Salinidad.RData")
tabla_describe_sal <- describe(Salinidad)
kable(round(tabla_describe_sal, 2),
caption = "Estadísticos descriptivos",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
scroll_box(width = "100%")
| vars | n | mean | sd | median | trimmed | mad | min | max | range | skew | kurtosis | se | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Biomasa | 1 | 45 | 1082.17 | 546.29 | 991.83 | 1022.02 | 526.40 | 369.82 | 2337.33 | 1967.50 | 0.91 | -0.02 | 81.44 |
| pH | 2 | 45 | 4.61 | 1.25 | 4.45 | 4.46 | 1.41 | 3.20 | 7.45 | 4.25 | 0.87 | -0.03 | 0.19 |
| Salinidad | 3 | 45 | 30.27 | 3.72 | 30.00 | 30.14 | 4.45 | 24.00 | 38.00 | 14.00 | 0.31 | -1.04 | 0.55 |
| Zinc | 4 | 45 | 17.83 | 8.27 | 19.24 | 18.40 | 6.62 | 0.21 | 31.29 | 31.08 | -0.66 | -0.06 | 1.23 |
| Potasio | 5 | 45 | 797.38 | 297.58 | 773.30 | 778.48 | 352.09 | 350.73 | 1441.67 | 1090.94 | 0.48 | -1.00 | 44.36 |
No hay datos faltantes en ninguna de las 45 muestras. Las cinco variables están en escalas muy distintas entre sí (Biomasa y Potasio en cientos, pH en unidades de 3 a 7), lo que hace poco justo comparar directamente sus desviaciones estándar; por eso a continuación se calcula el coeficiente de variación de cada una.
cv_tabla_sal <- data.frame(
Variable = names(sapply(Salinidad, cv)),
CV = round(sapply(Salinidad, cv), 2)
)
kable(cv_tabla_sal,
caption = "Coeficiente de variación (%)",
col.names = c("Variable", "CV (%)"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Variable | CV (%) |
|---|---|
| Biomasa | 50.48 |
| pH | 27.22 |
| Salinidad | 12.29 |
| Zinc | 46.40 |
| Potasio | 37.32 |
La biomasa (CV ≈ 50%) y el zinc (CV ≈ 46%) son, por mucho, las variables más dispersas del conjunto; la salinidad (CV ≈ 12%) es la más estable entre muestras.
p1 <- ggplot(Salinidad, aes(x = Biomasa)) +
geom_histogram(bins = 10, fill = "#622B51", color = "white") +
theme_minimal() + labs(title = "Biomasa", x = "Biomasa (g)", y = "Frecuencia")
p2 <- ggplot(Salinidad, aes(x = pH)) +
geom_histogram(bins = 10, fill = "#84477C", color = "white") +
theme_minimal() + labs(title = "pH", x = "pH", y = "Frecuencia")
p3 <- ggplot(Salinidad, aes(x = Salinidad)) +
geom_histogram(bins = 10, fill = "#534166", color = "white") +
theme_minimal() + labs(title = "Salinidad", x = "Salinidad", y = "Frecuencia")
p4 <- ggplot(Salinidad, aes(x = Zinc)) +
geom_histogram(bins = 10, fill = "#7C92A1", color = "white") +
theme_minimal() + labs(title = "Zinc", x = "Zinc", y = "Frecuencia")
p5 <- ggplot(Salinidad, aes(x = Potasio)) +
geom_histogram(bins = 10, fill = "#401C39", color = "white") +
theme_minimal() + labs(title = "Potasio", x = "Potasio", y = "Frecuencia")
grid.arrange(p1, p2, p3, p4, p5, ncol = 3)
Biomasa y pH muestran una ligera cola hacia la derecha; Zinc, en cambio, tiene una cola hacia la izquierda, pista de que hay algunas muestras con valores muy bajos, algo que se confirma con los boxplots a continuación.
b1 <- ggplot(Salinidad, aes(y = Biomasa)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Biomasa") + theme(axis.text.x = element_blank())
b2 <- ggplot(Salinidad, aes(y = pH)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "pH") + theme(axis.text.x = element_blank())
b3 <- ggplot(Salinidad, aes(y = Salinidad)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Salinidad") + theme(axis.text.x = element_blank())
b4 <- ggplot(Salinidad, aes(y = Zinc)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Zinc") + theme(axis.text.x = element_blank())
b5 <- ggplot(Salinidad, aes(y = Potasio)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Potasio") + theme(axis.text.x = element_blank())
grid.arrange(b1, b2, b3, b4, b5, ncol = 3)
Solo el Zinc muestra puntos por fuera de los bigotes de la caja; el resto de variables no presenta valores fuera de rango. A continuación se identifican esos casos puntualmente.
outliers_zinc_sal <- boxplot.stats(Salinidad$Zinc)$out
outliers_tabla_sal <- data.frame(
Muestra = seq_along(outliers_zinc_sal),
Zinc = round(outliers_zinc_sal, 4)
)
kable(outliers_tabla_sal,
caption = "Valores atípicos detectados en Zinc",
col.names = c("N°", "Valor de Zinc"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| N° | Valor de Zinc |
|---|---|
| 1 | 0.3729 |
| 2 | 0.2703 |
| 3 | 0.3205 |
| 4 | 0.2648 |
| 5 | 0.2105 |
Son 5 muestras con Zinc entre 0.21 y 0.37, muy por debajo del resto, siendo un grupo de valores particular dentro de la base.
En conjunto, la biomasa y el zinc son las variables con mayor variabilidad relativa (CV ≈ 50% y 46%), mientras que la salinidad es la más estable (CV ≈ 12%); el pH tiene una dispersión intermedia (CV ≈ 27%) y el potasio se ubica también en un nivel medio-alto (CV ≈ 37%). El zinc es la única variable con valores atípicos identificados.
matriz_cor_sal <- cor(Salinidad[, c("Biomasa", "pH", "Salinidad", "Zinc", "Potasio")],
method = "pearson")
kable(round(matriz_cor_sal, 3),
caption = "Matriz de correlación de Pearson",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Biomasa | pH | Salinidad | Zinc | Potasio | |
|---|---|---|---|---|---|
| Biomasa | 1.000 | 0.928 | -0.067 | -0.781 | -0.073 |
| pH | 0.928 | 1.000 | -0.045 | -0.720 | 0.032 |
| Salinidad | -0.067 | -0.045 | 1.000 | -0.427 | -0.020 |
| Zinc | -0.781 | -0.720 | -0.427 | 1.000 | 0.079 |
| Potasio | -0.073 | 0.032 | -0.020 | 0.079 | 1.000 |
cor_biomasa_sal <- data.frame(
Variable = c("pH", "Salinidad", "Zinc", "Potasio"),
Correlacion = round(matriz_cor_sal["Biomasa", c("pH", "Salinidad", "Zinc", "Potasio")], 3)
)
kable(cor_biomasa_sal,
caption = "Correlación de Pearson entre Biomasa y cada covariable",
col.names = c("Variable", "r (Pearson)"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Variable | r (Pearson) |
|---|---|
| pH | 0.928 |
| Salinidad | -0.067 |
| Zinc | -0.781 |
| Potasio | -0.073 |
El pH (r = 0.928) y el Zinc (r = -0.781) destacan como las covariables de mayor peso: la primera con relación fuerte y positiva, la segunda fuerte pero negativa. Salinidad (r = -0.067) y Potasio (r = -0.073) prácticamente no se relacionan linealmente con la biomasa. Por tener la correlación más fuerte, el pH es la covariable elegida para el análisis de varianza del literal c).
s1 <- ggplot(Salinidad, aes(x = pH, y = Biomasa)) +
geom_point(color = "#622B51", size = 2) + theme_minimal() +
labs(title = "Biomasa vs pH", x = "pH", y = "Biomasa")
s2 <- ggplot(Salinidad, aes(x = Salinidad, y = Biomasa)) +
geom_point(color = "#534166", size = 2) + theme_minimal() +
labs(title = "Biomasa vs Salinidad", x = "Salinidad", y = "Biomasa")
s3 <- ggplot(Salinidad, aes(x = Zinc, y = Biomasa)) +
geom_point(color = "#84477C", size = 2) + theme_minimal() +
labs(title = "Biomasa vs Zinc", x = "Zinc", y = "Biomasa")
s4 <- ggplot(Salinidad, aes(x = Potasio, y = Biomasa)) +
geom_point(color = "#7C92A1", size = 2) + theme_minimal() +
labs(title = "Biomasa vs Potasio", x = "Potasio", y = "Biomasa")
grid.arrange(s1, s2, s3, s4, ncol = 2)
Los diagramas confirman visualmente lo que ya decía la matriz: la nube de puntos de Biomasa vs. pH sube de forma consistente, la de Biomasa vs. Zinc baja, y las otras dos (Salinidad y Potasio) se ven dispersas sin ninguna tendencia clara.
terciles_sal <- quantile(Salinidad$pH, probs = c(0, 1/3, 2/3, 1))
terciles_tabla_sal <- data.frame(
Percentil = names(terciles_sal),
pH = round(as.numeric(terciles_sal), 2)
)
kable(terciles_tabla_sal,
caption = "Puntos de corte (terciles) del pH",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Percentil | pH |
|---|---|
| 0% | 3.20 |
| 33.33333% | 3.88 |
| 66.66667% | 4.90 |
| 100% | 7.45 |
Salinidad$pH_nivel <- cut(Salinidad$pH,
breaks = terciles_sal,
labels = c("Bajo", "Medio", "Alto"),
include.lowest = TRUE)
conteo_tabla_sal <- as.data.frame(table(Salinidad$pH_nivel))
kable(conteo_tabla_sal,
caption = "Número de observaciones por nivel de pH",
col.names = c("Nivel", "N"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Nivel | N |
|---|---|
| Bajo | 15 |
| Medio | 15 |
| Alto | 15 |
Los terciles dejan tres grupos parejos (15 muestras cada uno), condición conveniente para las comparaciones que siguen.
anova_sal <- aov(Biomasa ~ pH_nivel, data = Salinidad)
anova_tabla_sal <- as.data.frame(summary(anova_sal)[[1]])
anova_tabla_sal <- round(anova_tabla_sal, 4)
kable(anova_tabla_sal,
caption = "Tabla ANOVA: Biomasa ~ pH_nivel",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
|---|---|---|---|---|---|
| pH_nivel | 2 | 7712683 | 3856341.6 | 29.8928 | 0 |
| Residuals | 42 | 5418235 | 129005.6 | NA | NA |
El nivel de pH resulta con un efecto altamente significativo sobre la biomasa (F(2,42) = 29.89, p < 0.001).
shapiro_res_sal <- shapiro.test(residuals(anova_sal))
levene_res_sal <- leveneTest(Biomasa ~ pH_nivel, data = Salinidad)
supuestos_tabla_sal <- data.frame(
Prueba = c("Shapiro-Wilk (normalidad)", "Levene (homogeneidad de varianzas)"),
Estadistico = c(round(shapiro_res_sal$statistic, 4), round(levene_res_sal$`F value`[1], 4)),
p_valor = c(round(shapiro_res_sal$p.value, 4), round(levene_res_sal$`Pr(>F)`[1], 4))
)
kable(supuestos_tabla_sal,
caption = "Verificación de supuestos del ANOVA",
col.names = c("Prueba", "Estadístico", "p-valor"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Prueba | Estadístico | p-valor |
|---|---|---|
| Shapiro-Wilk (normalidad) | 0.9732 | 0.3749 |
| Levene (homogeneidad de varianzas) | 8.6753 | 0.0007 |
Con p = 0.375, Shapiro-Wilk no rechaza la normalidad de los residuales. Levene sí rechaza la homogeneidad de varianzas (p = 0.0007), una limitación del análisis que conviene tener presente al leer los resultados que siguen.
posanova_sal <- LSD.test(anova_sal, trt = "pH_nivel")
kable(as.data.frame(posanova_sal$statistics),
caption = "Estadísticos generales del modelo",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| MSerror | Df | Mean | CV | t.value | LSD |
|---|---|---|---|---|---|
| 129005.6 | 42 | 1082.173 | 33.19004 | 2.018082 | 264.6747 |
kable(as.data.frame(posanova_sal$parameters),
caption = "Parámetros de la prueba LSD",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| test | p.ajusted | name.t | ntr | alpha |
|---|---|---|---|---|
| Fisher-LSD | none | pH_nivel | 3 | 0.05 |
grupos_tabla_sal <- posanova_sal$groups
grupos_tabla_sal$Nivel <- rownames(grupos_tabla_sal)
grupos_tabla_sal <- grupos_tabla_sal[, c("Nivel", "Biomasa", "groups")]
kable(grupos_tabla_sal,
caption = "Agrupamiento LSD — Nivel de pH",
col.names = c("Nivel de pH", "Biomasa promedio", "Grupo"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Nivel de pH | Biomasa promedio | Grupo |
|---|---|---|
| Alto | 1605.3853 | a |
| Medio | 1048.1093 | b |
| Bajo | 593.0233 | c |
Los tres niveles reciben letras distintas (a, b, c): Alto (1605.39 g), Medio (1048.11 g) y Bajo (593.02 g) difieren entre sí, en línea con la correlación positiva ya observada entre pH y biomasa.
Dos tipos de moluscos (A y B) fueron expuestos a tres concentraciones distintas de agua de mar (100%, 75% y 50%), registrando el consumo de oxígeno como la proporción de O2 por unidad de peso seco del organismo. El experimento sigue una estructura factorial 2×3 (tipo de molusco por concentración de agua), con 8 réplicas por combinación y 48 observaciones en total.
48Observaciones
2Tipos de molusco
3Concentraciones de agua
1Variable respuesta (Consumo O2)
load("moluscos.RData")
BD_moluscos <- BD_moluscos %>%
mutate(
c_agua = factor(c_agua, levels = c(100, 75, 50)),
molusco = factor(molusco)
)
tabla_molusco_mol <- as.data.frame(table(BD_moluscos$molusco))
kable(tabla_molusco_mol,
caption = "Frecuencia por tipo de molusco",
col.names = c("Molusco", "N"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Molusco | N |
|---|---|
| A | 24 |
| B | 24 |
tabla_agua_mol <- as.data.frame(table(BD_moluscos$c_agua))
kable(tabla_agua_mol,
caption = "Frecuencia por concentración de agua de mar",
col.names = c("Concentración (%)", "N"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Concentración (%) | N |
|---|---|
| 100 | 16 |
| 75 | 16 |
| 50 | 16 |
El diseño queda perfectamente balanceado: 24 observaciones por tipo de molusco y 16 por cada concentración de agua de mar.
resumen_o2_mol <- data.frame(
Estadistico = c("Mínimo", "1er Cuartil", "Mediana", "Media", "3er Cuartil",
"Máximo", "Desviación estándar"),
Valor = round(c(min(BD_moluscos$cons_o), quantile(BD_moluscos$cons_o, 0.25),
median(BD_moluscos$cons_o), mean(BD_moluscos$cons_o),
quantile(BD_moluscos$cons_o, 0.75), max(BD_moluscos$cons_o),
sd(BD_moluscos$cons_o)), 2)
)
kable(resumen_o2_mol,
caption = "Estadísticos descriptivos del consumo de O2",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Estadistico | Valor |
|---|---|
| Mínimo | 1.80 |
| 1er Cuartil | 6.31 |
| Mediana | 9.70 |
| Media | 9.30 |
| 3er Cuartil | 11.23 |
| Máximo | 18.80 |
| Desviación estándar | 3.68 |
ggplot(BD_moluscos, aes(x = cons_o)) +
geom_histogram(bins = 10, fill = "#622B51", color = "white") +
labs(title = "Distribución del consumo de O2", x = "Consumo de O2", y = "Frecuencia") +
theme_minimal()
ggplot(BD_moluscos, aes(y = cons_o)) +
geom_boxplot(fill = "#D9CFE0") +
labs(title = "Boxplot del consumo de O2", y = "Consumo de O2") +
theme_minimal()
La media (9.30) y la mediana (9.70) del consumo de O2 son cercanas, con una dispersión considerable (sd = 3.68, CV ≈ 40%). El boxplot marca un valor atípico (18.8), el máximo de la muestra. Este resumen todavía mezcla las seis combinaciones posibles de molusco y concentración; el literal b) desagrega ese comportamiento.
ggplot(BD_moluscos, aes(x = c_agua, y = cons_o, fill = molusco)) +
geom_boxplot() +
scale_fill_manual(values = c("#622B51", "#7C92A1")) +
labs(title = "Consumo de O2 según concentración de agua y tipo de molusco",
x = "Concentración de agua de mar (%)",
y = "Consumo de O2",
fill = "Molusco") +
theme_minimal()
medias_mol <- BD_moluscos %>%
group_by(c_agua, molusco) %>%
summarise(media_cons_o = round(mean(cons_o), 2), .groups = "drop")
kable(medias_mol,
caption = "Media de consumo de O2 por combinación molusco x concentración",
col.names = c("Concentración (%)", "Molusco", "Media Consumo O2"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Concentración (%) | Molusco | Media Consumo O2 |
|---|---|---|
| 100 | A | 9.94 |
| 100 | B | 7.41 |
| 75 | A | 7.89 |
| 75 | B | 6.10 |
| 50 | A | 12.18 |
| 50 | B | 12.33 |
En 100% y 75%, el molusco A consume en promedio más oxígeno que el B (9.94 frente a 7.41, y 7.89 frente a 6.10); en 50%, ambos quedan prácticamente igualados (12.18 frente a 12.33).
ggplot(medias_mol, aes(x = c_agua, y = media_cons_o, color = molusco, group = molusco)) +
geom_point(size = 3) +
geom_line(linewidth = 1) +
scale_color_manual(values = c("#401C39", "#84477C")) +
labs(title = "Gráfico de interacción: concentración x tipo de molusco",
x = "Concentración de agua de mar (%)",
y = "Media de consumo de O2",
color = "Molusco") +
theme_minimal()
Las dos líneas dibujan la misma forma de “V” frente a la concentración; bajan de 100% a 75% y suben con fuerza en 50%, lo que ya sugiere visualmente que el patrón general no depende del tipo de molusco. Que la brecha entre A y B se cierre justo en la concentración más baja podría insinuar una interacción leve, algo que el ANOVA permite confirmar o descartar formalmente.
modelo_mol <- aov(cons_o ~ molusco * c_agua, data = BD_moluscos)
anova_tabla_mol <- as.data.frame(summary(modelo_mol)[[1]])
anova_tabla_mol <- round(anova_tabla_mol, 4)
kable(anova_tabla_mol,
caption = "Tabla ANOVA: Consumo de O2 ~ Molusco * Concentración de agua",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
|---|---|---|---|---|---|
| molusco | 1 | 23.2269 | 23.2269 | 2.6508 | 0.1110 |
| c_agua | 2 | 230.8160 | 115.4080 | 13.1712 | 0.0000 |
| molusco:c_agua | 2 | 15.3563 | 7.6781 | 0.8763 | 0.4238 |
| Residuals | 42 | 368.0112 | 8.7622 | NA | NA |
shapiro_res_mol <- shapiro.test(residuals(modelo_mol))
levene_res_mol <- leveneTest(cons_o ~ molusco * c_agua, data = BD_moluscos)
supuestos_tabla_mol <- data.frame(
Prueba = c("Shapiro-Wilk (normalidad)", "Levene (homogeneidad de varianzas)"),
Estadistico = c(round(shapiro_res_mol$statistic, 4), round(levene_res_mol$`F value`[1], 4)),
p_valor = c(round(shapiro_res_mol$p.value, 4), round(levene_res_mol$`Pr(>F)`[1], 4))
)
kable(supuestos_tabla_mol,
caption = "Verificación de supuestos del ANOVA",
col.names = c("Prueba", "Estadístico", "p-valor"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Prueba | Estadístico | p-valor |
|---|---|---|
| Shapiro-Wilk (normalidad) | 0.9582 | 0.0857 |
| Levene (homogeneidad de varianzas) | 0.1723 | 0.9715 |
Shapiro-Wilk (p = 0.086) y Levene (p = 0.972) están ambos por encima de 0.05: ninguno de los dos supuestos se rechaza, así que el modelo es válido tal como fue planteado.
El tipo de molusco no resulta significativo (F(1,42) = 2.65, p = 0.111), y tampoco la interacción molusco × concentración (F(2,42) = 0.88, p = 0.424): el efecto de la concentración es, entonces, el mismo para los dos moluscos, pese a la diferencia visual del literal b). La concentración de agua sí tiene un efecto muy marcado (F(2,42) = 13.17, p < 0.001), y es el único factor sobre el que tiene sentido hacer comparaciones post-hoc.
posanova_mol <- LSD.test(modelo_mol, "c_agua", console = FALSE)
kable(as.data.frame(posanova_mol$statistics),
caption = "Estadísticos generales del modelo",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| MSerror | Df | Mean | CV | t.value | LSD |
|---|---|---|---|---|---|
| 8.76217 | 42 | 9.304792 | 31.8126 | 2.018082 | 2.112028 |
grupos_tabla_mol <- posanova_mol$groups
grupos_tabla_mol$Concentracion <- rownames(grupos_tabla_mol)
grupos_tabla_mol <- grupos_tabla_mol[, c("Concentracion", "cons_o", "groups")]
kable(grupos_tabla_mol,
caption = "Agrupamiento LSD — Concentración de agua de mar",
col.names = c("Concentración (%)", "Consumo O2 promedio", "Grupo"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Concentración (%) | Consumo O2 promedio | Grupo |
|---|---|---|
| 50 | 12.25062 | a |
| 100 | 8.67125 | b |
| 75 | 6.99250 | b |
50% queda en un grupo aparte (“a”), con el consumo más alto (12.25); 100% (8.67) y 75% (6.99) comparten grupo (“b”), sin diferencia entre sí. La caída de 100% a 75% no llega a ser significativa, pero el salto al llegar a 50% sí lo es. Es un indicio de que una dilución fuerte del agua de mar exige a los moluscos, sin importar el tipo, un consumo de oxígeno notoriamente mayor.
Con el fin de evaluar el efecto del uso del suelo sobre la biodiversidad de anfibios en una reserva forestal, se establecieron parcelas de muestreo en cuatro tipos de hábitat que representan un gradiente de intervención antrópica: bosque primario, bosque secundario, sistema silvopastoril y potrero. En cada una de las 52 parcelas (13 por hábitat) se registró la riqueza de especies, el índice de diversidad de Shannon-Wiener y la altitud (m.s.n.m.) del sitio de muestreo.
52Parcelas
4Tipos de hábitat
13Parcelas por hábitat
3Variables registradas
load("Biodiversidad.RData")
tabla_describe_bio <- describe(BD_biodiversidad[, c("Riqueza", "Shannon", "Altitud")])
kable(round(tabla_describe_bio, 2),
caption = "Estadísticos descriptivos",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
scroll_box(width = "100%")
| vars | n | mean | sd | median | trimmed | mad | min | max | range | skew | kurtosis | se | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Riqueza | 1 | 52 | 9.73 | 4.37 | 9.50 | 9.60 | 5.19 | 2.00 | 21.00 | 19.00 | 0.28 | -0.72 | 0.61 |
| Shannon | 2 | 52 | 1.76 | 0.61 | 1.85 | 1.76 | 0.64 | 0.67 | 2.98 | 2.31 | 0.04 | -0.84 | 0.08 |
| Altitud | 3 | 52 | 1243.89 | 172.71 | 1254.80 | 1240.59 | 215.64 | 950.90 | 1600.80 | 649.90 | 0.09 | -1.26 | 23.95 |
cv_tabla_bio <- data.frame(
Variable = c("Riqueza", "Shannon", "Altitud"),
CV = round(sapply(BD_biodiversidad[, c("Riqueza", "Shannon", "Altitud")], cv), 2)
)
kable(cv_tabla_bio,
caption = "Coeficiente de variación (%)",
col.names = c("Variable", "CV (%)"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Variable | CV (%) |
|---|---|
| Riqueza | 44.92 |
| Shannon | 34.44 |
| Altitud | 13.88 |
Las 52 parcelas están completas, sin datos faltantes, y repartidas en partes iguales entre los 4 hábitats (13 cada uno). En cuanto a dispersión relativa, Riqueza (CV ≈ 45%) es la más variable, seguida de Shannon (CV ≈ 34%); la Altitud (CV ≈ 14%) es comparativamente estable.
b1b <- ggplot(BD_biodiversidad, aes(y = Riqueza)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Riqueza") + theme(axis.text.x = element_blank())
b2b <- ggplot(BD_biodiversidad, aes(y = Shannon)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Shannon") + theme(axis.text.x = element_blank())
b3b <- ggplot(BD_biodiversidad, aes(y = Altitud)) +
geom_boxplot(fill = "#D9CFE0") + theme_minimal() +
labs(title = "Altitud") + theme(axis.text.x = element_blank())
grid.arrange(b1b, b2b, b3b, ncol = 3)
Ninguna de las tres cajas muestra puntos por fuera de los bigotes: no hay valores atípicos evidentes en ninguna variable.
p1b <- ggplot(BD_biodiversidad, aes(x = Riqueza)) +
geom_histogram(bins = 10, fill = "#622B51", color = "white") +
theme_minimal() + labs(title = "Riqueza de especies", x = "Riqueza", y = "Frecuencia")
p2b <- ggplot(BD_biodiversidad, aes(x = Shannon)) +
geom_histogram(bins = 10, fill = "#84477C", color = "white") +
theme_minimal() + labs(title = "Índice de Shannon", x = "Shannon", y = "Frecuencia")
p3b <- ggplot(BD_biodiversidad, aes(x = Altitud)) +
geom_histogram(bins = 10, fill = "#534166", color = "white") +
theme_minimal() + labs(title = "Altitud", x = "Altitud (m.s.n.m.)", y = "Frecuencia")
grid.arrange(p1b, p2b, p3b, ncol = 3)
Riqueza y Altitud tienen una ligera cola hacia la derecha; Shannon es prácticamente simétrica. Al estar mezclados aquí los 4 hábitats, parte de esa forma responde a la combinación de grupos distintos, lo que se desagrega en el literal b).
ggplot(BD_biodiversidad, aes(x = Altitud, y = Shannon)) +
geom_point(aes(color = Habitat), size = 2) +
scale_color_manual(values = c("#401C39", "#622B51", "#84477C", "#7C92A1")) +
geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed") +
theme_minimal() +
labs(title = "Shannon vs Altitud", x = "Altitud (m.s.n.m.)", y = "Índice de Shannon")
cor_alt_bio <- cor.test(BD_biodiversidad$Altitud, BD_biodiversidad$Shannon, method = "pearson")
cor_tabla_bio <- data.frame(
Relacion = "Altitud vs Shannon",
r = round(cor_alt_bio$estimate, 3),
p_valor = signif(cor_alt_bio$p.value, 3)
)
kable(cor_tabla_bio,
caption = "Correlación de Pearson entre Altitud y Shannon",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Relacion | r | p_valor |
|---|---|---|
| Altitud vs Shannon | 0.752 | 0 |
La correlación es positiva y fuerte (r = 0.752, p < 0.001): a mayor altitud, mayor diversidad. Pero los puntos se agrupan por color siguiendo el mismo gradiente que la altitud, lo que sugiere que buena parte de esa relación refleja que los hábitats menos intervenidos están también en las zonas más altas de la reserva, más que un efecto altitudinal puro.
BD_biodiversidad$Habitat <- factor(BD_biodiversidad$Habitat,
levels = c("Bosque primario", "Bosque secundario",
"Sistema silvopastoril", "Potrero"))
g1b <- ggplot(BD_biodiversidad, aes(x = Habitat, y = Riqueza, fill = Habitat)) +
geom_boxplot() + theme_minimal() +
scale_fill_manual(values = c("#401C39", "#622B51", "#84477C", "#D9CFE0")) +
labs(title = "Riqueza de especies por hábitat", x = "", y = "Riqueza") +
theme(axis.text.x = element_text(angle = 20, hjust = 1), legend.position = "none")
g2b <- ggplot(BD_biodiversidad, aes(x = Habitat, y = Shannon, fill = Habitat)) +
geom_boxplot() + theme_minimal() +
scale_fill_manual(values = c("#401C39", "#622B51", "#84477C", "#D9CFE0")) +
labs(title = "Índice de Shannon por hábitat", x = "", y = "Shannon") +
theme(axis.text.x = element_text(angle = 20, hjust = 1), legend.position = "none")
grid.arrange(g1b, g2b, ncol = 2)
tabla_grupo_bio <- BD_biodiversidad %>%
group_by(Habitat) %>%
summarise(
n = n(),
Riqueza_media = round(mean(Riqueza), 2),
Riqueza_sd = round(sd(Riqueza), 2),
Shannon_media = round(mean(Shannon), 2),
Shannon_sd = round(sd(Shannon), 2)
)
kable(tabla_grupo_bio,
caption = "Riqueza y Shannon promedio por tipo de hábitat",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Habitat | n | Riqueza_media | Riqueza_sd | Shannon_media | Shannon_sd |
|---|---|---|---|---|---|
| Bosque primario | 13 | 14.77 | 2.74 | 2.47 | 0.38 |
| Bosque secundario | 13 | 11.08 | 3.01 | 1.97 | 0.22 |
| Sistema silvopastoril | 13 | 8.08 | 2.50 | 1.60 | 0.28 |
| Potrero | 13 | 5.00 | 1.29 | 1.00 | 0.24 |
Riqueza y Shannon bajan de forma ordenada a lo largo del gradiente de intervención: máximos en bosque primario, mínimos en potrero. A mayor intervención humana, menor biodiversidad de anfibios registrada.
anova_bio <- aov(Shannon ~ Habitat, data = BD_biodiversidad)
anova_tabla_bio <- as.data.frame(summary(anova_bio)[[1]])
anova_tabla_bio <- round(anova_tabla_bio, 4)
kable(anova_tabla_bio,
caption = "Tabla ANOVA: Shannon ~ Habitat",
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
|---|---|---|---|---|---|
| Habitat | 3 | 14.8624 | 4.9541 | 60.6112 | 0 |
| Residuals | 48 | 3.9233 | 0.0817 | NA | NA |
El hábitat tiene un efecto altamente significativo sobre el Shannon (F(3,48) = 60.61, p < 0.001), al menos uno de los cuatro hábitats difiere de los demás.
shapiro_res_bio <- shapiro.test(residuals(anova_bio))
levene_res_bio <- leveneTest(Shannon ~ Habitat, data = BD_biodiversidad)
supuestos_tabla_bio <- data.frame(
Prueba = c("Shapiro-Wilk (normalidad)", "Levene (homogeneidad de varianzas)"),
Estadistico = c(round(shapiro_res_bio$statistic, 4), round(levene_res_bio$`F value`[1], 4)),
p_valor = c(round(shapiro_res_bio$p.value, 4), round(levene_res_bio$`Pr(>F)`[1], 4))
)
kable(supuestos_tabla_bio,
caption = "Verificación de supuestos del ANOVA",
col.names = c("Prueba", "Estadístico", "p-valor"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Prueba | Estadístico | p-valor |
|---|---|---|
| Shapiro-Wilk (normalidad) | 0.9785 | 0.4625 |
| Levene (homogeneidad de varianzas) | 1.2768 | 0.2930 |
Shapiro-Wilk (p = 0.463) y Levene (p = 0.293) están ambos por encima de 0.05: ninguno de los dos supuestos se rechaza, así que el modelo y su post-hoc son confiables.
posanova_bio <- LSD.test(anova_bio, trt = "Habitat")
kable(as.data.frame(posanova_bio$statistics),
caption = "Estadísticos generales del modelo",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| MSerror | Df | Mean | CV | t.value | LSD |
|---|---|---|---|---|---|
| 0.0817362 | 48 | 1.762308 | 16.22279 | 2.010635 | 0.2254674 |
kable(as.data.frame(posanova_bio$parameters),
caption = "Parámetros de la prueba LSD",
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| test | p.ajusted | name.t | ntr | alpha |
|---|---|---|---|---|
| Fisher-LSD | none | Habitat | 4 | 0.05 |
grupos_tabla_bio <- posanova_bio$groups
grupos_tabla_bio$Habitat <- rownames(grupos_tabla_bio)
grupos_tabla_bio <- grupos_tabla_bio[, c("Habitat", "Shannon", "groups")]
kable(grupos_tabla_bio,
caption = "Agrupamiento LSD — Tipo de hábitat",
col.names = c("Hábitat", "Shannon promedio", "Grupo"),
row.names = FALSE,
table.attr = "class='tabla-verde'") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
| Hábitat | Shannon promedio | Grupo |
|---|---|---|
| Bosque primario | 2.467692 | a |
| Bosque secundario | 1.974615 | b |
| Sistema silvopastoril | 1.603077 | c |
| Potrero | 1.003846 | d |
Los cuatro hábitats reciben letras distintas (a, b, c, d): Bosque primario (2.47), Bosque secundario (1.97), Sistema silvopastoril (1.60) y Potrero (1.00) difieren todos entre sí, confirmando el gradiente decreciente ya sugerido en el análisis bivariado.