# Paquetes necesarios -------------------------------------------------------
paquetes <- c("tidyverse", "ggplot2", "corrplot", "psych", "rstatix",
"vegan", "MASS", "factoextra", "FactoMineR", "knitr",
"broom", "GGally")
instalar_faltantes <- paquetes[!paquetes %in% installed.packages()[, "Package"]]
if (length(instalar_faltantes) > 0) install.packages(instalar_faltantes)
invisible(lapply(paquetes, library, character.only = TRUE))Análisis morfométrico comparativo: Tityus paraguayensis vs Tityus crypticus sp. nov.
De estadística descriptiva a multivariada y predictiva
0. Advertencia metodológica importante
Antes de cualquier análisis, hay que ser honestos con el tamaño de muestra:
- Tityus paraguayensis: n = 7
- Tityus crypticus sp. nov.: n = 4
Con muestras tan pequeñas (especialmente n = 4), pruebas como Shapiro-Wilk tienen muy poco poder estadístico, los intervalos de confianza son muy amplios, y técnicas como PCA con elipses o modelos predictivos con partición train/test no son confiables en sentido inferencial. Este script los incluye de todas formas porque son estándar en papers de morfometría taxonómica con series tipo pequeñas (común en Tityus), pero en cada sección se indica si el resultado es confirmatorio o solo exploratorio/descriptivo.
1. Carga y preparación de datos
datos <- read.csv("datos_escorpiones.csv", stringsAsFactors = FALSE)
datos$Especie <- factor(datos$Especie,
levels = c("Tityus_paraguayensis", "Tityus_crypticus_sp_nov"))
# Variables morfométricas (todas numéricas, excluyendo Especie)
vars_morfo <- names(datos)[-1]
str(datos)'data.frame': 11 obs. of 9 variables:
$ Especie : Factor w/ 2 levels "Tityus_paraguayensis",..: 1 1 1 1 1 1 1 2 2 2 ...
$ Total_length : num 41.5 40.7 39.4 42.3 40.1 ...
$ Prosoma_length : num 5 5.37 5.61 5.98 5.49 5.61 5.61 4.63 4.88 4.51 ...
$ Mesosoma_length : num 10.67 10.24 8.17 10.61 9.15 ...
$ Chela_length : num 7.44 7.44 7.68 7.8 7.44 7.56 7.44 7.38 7.56 6.95 ...
$ Chela_width : num 2.07 1.95 2.32 2.38 2.07 2.07 2.07 2.2 2.32 2.07 ...
$ Metasoma_V_length: num 5.49 5.37 5.73 5.85 5.85 5.85 5.73 4.63 4.39 4.39 ...
$ Metasoma_V_width : num 2.44 2.44 2.62 2.68 2.44 2.44 2.56 2.32 2.32 2.2 ...
$ Length_Telson : num 4.02 3.9 4.51 4.39 3.9 4.39 4.39 3.54 3.54 3.29 ...
kable(datos)| Especie | Total_length | Prosoma_length | Mesosoma_length | Chela_length | Chela_width | Metasoma_V_length | Metasoma_V_width | Length_Telson |
|---|---|---|---|---|---|---|---|---|
| Tityus_paraguayensis | 41.46 | 5.00 | 10.67 | 7.44 | 2.07 | 5.49 | 2.44 | 4.02 |
| Tityus_paraguayensis | 40.73 | 5.37 | 10.24 | 7.44 | 1.95 | 5.37 | 2.44 | 3.90 |
| Tityus_paraguayensis | 39.39 | 5.61 | 8.17 | 7.68 | 2.32 | 5.73 | 2.62 | 4.51 |
| Tityus_paraguayensis | 42.32 | 5.98 | 10.61 | 7.80 | 2.38 | 5.85 | 2.68 | 4.39 |
| Tityus_paraguayensis | 40.12 | 5.49 | 9.15 | 7.44 | 2.07 | 5.85 | 2.44 | 3.90 |
| Tityus_paraguayensis | 41.71 | 5.61 | 10.73 | 7.56 | 2.07 | 5.85 | 2.44 | 4.39 |
| Tityus_paraguayensis | 41.71 | 5.61 | 10.61 | 7.44 | 2.07 | 5.73 | 2.56 | 4.39 |
| Tityus_crypticus_sp_nov | 32.44 | 4.63 | 6.22 | 7.38 | 2.20 | 4.63 | 2.32 | 3.54 |
| Tityus_crypticus_sp_nov | 33.54 | 4.88 | 7.32 | 7.56 | 2.32 | 4.39 | 2.32 | 3.54 |
| Tityus_crypticus_sp_nov | 32.44 | 4.51 | 7.32 | 6.95 | 2.07 | 4.39 | 2.20 | 3.29 |
| Tityus_crypticus_sp_nov | 33.78 | 4.88 | 7.56 | 7.32 | 2.44 | 4.76 | 2.20 | 3.54 |
Verificación de tamaño de muestra por grupo (clave para interpretar todo lo que sigue):
datos %>%
count(Especie, name = "n") Especie n
1 Tityus_paraguayensis 7
2 Tityus_crypticus_sp_nov 4
2. Estadística descriptiva
# Resumen tipo "tabla morfométrica" de paper taxonómico
resumen_desc <- datos %>%
pivot_longer(cols = all_of(vars_morfo), names_to = "Variable", values_to = "Valor") %>%
group_by(Especie, Variable) %>%
summarise(
n = n(),
media = mean(Valor),
de = sd(Valor),
cv_pct = (de / media) * 100,
minimo = min(Valor),
maximo = max(Valor),
.groups = "drop"
) %>%
arrange(Variable, Especie)
kable(resumen_desc, digits = 2,
caption = "Estadística descriptiva por especie y variable morfométrica")| Especie | Variable | n | media | de | cv_pct | minimo | maximo |
|---|---|---|---|---|---|---|---|
| Tityus_paraguayensis | Chela_length | 7 | 7.54 | 0.15 | 1.93 | 7.44 | 7.80 |
| Tityus_crypticus_sp_nov | Chela_length | 4 | 7.30 | 0.26 | 3.51 | 6.95 | 7.56 |
| Tityus_paraguayensis | Chela_width | 7 | 2.13 | 0.16 | 7.30 | 1.95 | 2.38 |
| Tityus_crypticus_sp_nov | Chela_width | 4 | 2.26 | 0.16 | 7.04 | 2.07 | 2.44 |
| Tityus_paraguayensis | Length_Telson | 7 | 4.21 | 0.26 | 6.24 | 3.90 | 4.51 |
| Tityus_crypticus_sp_nov | Length_Telson | 4 | 3.48 | 0.12 | 3.59 | 3.29 | 3.54 |
| Tityus_paraguayensis | Mesosoma_length | 7 | 10.03 | 0.99 | 9.85 | 8.17 | 10.73 |
| Tityus_crypticus_sp_nov | Mesosoma_length | 4 | 7.11 | 0.60 | 8.46 | 6.22 | 7.56 |
| Tityus_paraguayensis | Metasoma_V_length | 7 | 5.70 | 0.19 | 3.38 | 5.37 | 5.85 |
| Tityus_crypticus_sp_nov | Metasoma_V_length | 4 | 4.54 | 0.18 | 4.05 | 4.39 | 4.76 |
| Tityus_paraguayensis | Metasoma_V_width | 7 | 2.52 | 0.10 | 4.06 | 2.44 | 2.68 |
| Tityus_crypticus_sp_nov | Metasoma_V_width | 4 | 2.26 | 0.07 | 3.07 | 2.20 | 2.32 |
| Tityus_paraguayensis | Prosoma_length | 7 | 5.52 | 0.30 | 5.38 | 5.00 | 5.98 |
| Tityus_crypticus_sp_nov | Prosoma_length | 4 | 4.72 | 0.19 | 3.93 | 4.51 | 4.88 |
| Tityus_paraguayensis | Total_length | 7 | 41.06 | 1.03 | 2.51 | 39.39 | 42.32 |
| Tityus_crypticus_sp_nov | Total_length | 4 | 33.05 | 0.71 | 2.15 | 32.44 | 33.78 |
Interpretación: el CV% (coeficiente de variación) ayuda a ver qué variables son más variables dentro de cada especie. Variables con CV bajo y consistentes entre individuos suelen ser más útiles como caracteres diagnósticos.
3. Razones morfométricas (índices diagnósticos)
En taxonomía de Tityus las razones (no solo las medidas brutas) suelen ser las que separan especies, porque controlan el efecto del tamaño corporal general.
datos_razones <- datos %>%
mutate(
Chela_L_W = Chela_length / Chela_width,
MetasomaV_L_W = Metasoma_V_length / Metasoma_V_width,
Mesosoma_Total = Mesosoma_length / Total_length,
Prosoma_Total = Prosoma_length / Total_length,
Telson_MetasomaV = Length_Telson / Metasoma_V_length
)
vars_razones <- c("Chela_L_W", "MetasomaV_L_W", "Mesosoma_Total",
"Prosoma_Total", "Telson_MetasomaV")
resumen_razones <- datos_razones %>%
pivot_longer(cols = all_of(vars_razones), names_to = "Razon", values_to = "Valor") %>%
group_by(Especie, Razon) %>%
summarise(media = mean(Valor), de = sd(Valor), .groups = "drop")
kable(resumen_razones, digits = 3,
caption = "Razones morfométricas por especie")| Especie | Razon | media | de |
|---|---|---|---|
| Tityus_paraguayensis | Chela_L_W | 3.548 | 0.191 |
| Tityus_paraguayensis | Mesosoma_Total | 0.244 | 0.019 |
| Tityus_paraguayensis | MetasomaV_L_W | 2.265 | 0.094 |
| Tityus_paraguayensis | Prosoma_Total | 0.135 | 0.007 |
| Tityus_paraguayensis | Telson_MetasomaV | 0.740 | 0.038 |
| Tityus_crypticus_sp_nov | Chela_L_W | 3.243 | 0.168 |
| Tityus_crypticus_sp_nov | Mesosoma_Total | 0.215 | 0.016 |
| Tityus_crypticus_sp_nov | MetasomaV_L_W | 2.012 | 0.112 |
| Tityus_crypticus_sp_nov | Prosoma_Total | 0.143 | 0.003 |
| Tityus_crypticus_sp_nov | Telson_MetasomaV | 0.766 | 0.028 |
datos_razones %>%
pivot_longer(cols = all_of(vars_razones), names_to = "Razon", values_to = "Valor") %>%
ggplot(aes(x = Especie, y = Valor, fill = Especie)) +
geom_boxplot(alpha = 0.6) +
geom_jitter(width = 0.1, size = 2) +
facet_wrap(~Razon, scales = "free_y") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 30, hjust = 1)) +
labs(title = "Razones morfométricas por especie", y = "Valor de la razón", x = NULL)4. Exploración gráfica de variables crudas
datos %>%
pivot_longer(cols = all_of(vars_morfo), names_to = "Variable", values_to = "Valor") %>%
ggplot(aes(x = Especie, y = Valor, fill = Especie)) +
geom_boxplot(alpha = 0.6, outlier.shape = NA) +
geom_jitter(width = 0.1, size = 2) +
facet_wrap(~Variable, scales = "free_y") +
theme_minimal() +
theme(axis.text.x = element_blank(), legend.position = "bottom") +
labs(title = "Variables morfométricas crudas por especie", x = NULL, y = "mm")ggplot(datos, aes(x = Chela_length, y = Chela_width, color = Especie)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE, linetype = "dashed") +
theme_minimal() +
labs(title = "Largo vs ancho de quela", x = "Largo quela (mm)", y = "Ancho quela (mm)")5. Supuestos: normalidad y homocedasticidad
⚠️ Con n = 4 y n = 7, Shapiro-Wilk tiene muy poco poder. Tómese como orientativo, no decisivo.
normalidad <- datos %>%
pivot_longer(cols = all_of(vars_morfo), names_to = "Variable", values_to = "Valor") %>%
group_by(Especie, Variable) %>%
summarise(
shapiro_p = tryCatch(shapiro.test(Valor)$p.value, error = function(e) NA),
.groups = "drop"
)
kable(normalidad, digits = 3,
caption = "p-valores de Shapiro-Wilk por especie y variable (n bajo: interpretar con cautela)")| Especie | Variable | shapiro_p |
|---|---|---|
| Tityus_paraguayensis | Chela_length | 0.022 |
| Tityus_paraguayensis | Chela_width | 0.055 |
| Tityus_paraguayensis | Length_Telson | 0.054 |
| Tityus_paraguayensis | Mesosoma_length | 0.016 |
| Tityus_paraguayensis | Metasoma_V_length | 0.055 |
| Tityus_paraguayensis | Metasoma_V_width | 0.025 |
| Tityus_paraguayensis | Prosoma_length | 0.518 |
| Tityus_paraguayensis | Total_length | 0.625 |
| Tityus_crypticus_sp_nov | Chela_length | 0.628 |
| Tityus_crypticus_sp_nov | Chela_width | 0.976 |
| Tityus_crypticus_sp_nov | Length_Telson | 0.001 |
| Tityus_crypticus_sp_nov | Mesosoma_length | 0.076 |
| Tityus_crypticus_sp_nov | Metasoma_V_length | 0.236 |
| Tityus_crypticus_sp_nov | Metasoma_V_width | 0.024 |
| Tityus_crypticus_sp_nov | Prosoma_length | 0.218 |
| Tityus_crypticus_sp_nov | Total_length | 0.108 |
homogeneidad <- map_dfr(vars_morfo, function(v) {
f <- as.formula(paste(v, "~ Especie"))
lev <- rstatix::levene_test(datos, formula = f)
lev$Variable <- v
lev
})
kable(homogeneidad, digits = 3,
caption = "Prueba de Levene (homogeneidad de varianzas) por variable")| df1 | df2 | statistic | p | Variable |
|---|---|---|---|---|
| 1 | 9 | 0.221 | 0.649 | Total_length |
| 1 | 9 | 0.091 | 0.770 | Prosoma_length |
| 1 | 9 | 0.333 | 0.578 | Mesosoma_length |
| 1 | 9 | 0.433 | 0.527 | Chela_length |
| 1 | 9 | 0.120 | 0.737 | Chela_width |
| 1 | 9 | 0.048 | 0.831 | Metasoma_V_length |
| 1 | 9 | 0.107 | 0.751 | Metasoma_V_width |
| 1 | 9 | 1.348 | 0.275 | Length_Telson |
6. Estadística confirmatoria univariada (comparación entre especies)
Dado el tamaño de muestra y la probable no-normalidad, se usa Mann-Whitney U (Wilcoxon) como prueba principal (más robusta), reportando t-test como referencia. Se aplica corrección de Holm por comparaciones múltiples (8 variables).
comparaciones <- map_dfr(vars_morfo, function(v) {
f <- as.formula(paste(v, "~ Especie"))
wilcox <- wilcox.test(f, data = datos)
ttest <- t.test(f, data = datos)
tibble(
Variable = v,
p_wilcoxon = wilcox.test(f, data = datos)$p.value,
p_ttest = t.test(f, data = datos)$p.value
)
})
comparaciones <- comparaciones %>%
mutate(
p_wilcoxon_holm = p.adjust(p_wilcoxon, method = "holm"),
p_ttest_holm = p.adjust(p_ttest, method = "holm")
)
kable(comparaciones, digits = 4,
caption = "Comparación univariada entre especies (Wilcoxon y t-test, con corrección de Holm)")| Variable | p_wilcoxon | p_ttest | p_wilcoxon_holm | p_ttest_holm |
|---|---|---|---|---|
| Total_length | 0.0104 | 0.0000 | 0.0696 | 0.0000 |
| Prosoma_length | 0.0099 | 0.0004 | 0.0696 | 0.0017 |
| Mesosoma_length | 0.0104 | 0.0002 | 0.0696 | 0.0010 |
| Chela_length | 0.0810 | 0.1574 | 0.1620 | 0.3148 |
| Chela_width | 0.2332 | 0.2522 | 0.2332 | 0.3148 |
| Metasoma_V_length | 0.0097 | 0.0000 | 0.0696 | 0.0002 |
| Metasoma_V_width | 0.0087 | 0.0009 | 0.0696 | 0.0028 |
| Length_Telson | 0.0092 | 0.0002 | 0.0696 | 0.0009 |
Lectura: con n tan bajo, exigir significancia tras corrección de Holm es un estándar muy estricto; aun si algunas variables no la superan, las diferencias en magnitud (ver sección de descriptivos y razones) siguen siendo informativas para la diagnosis taxonómica, apoyadas en evidencia morfológica cualitativa adicional que tú ya tienes en tu trabajo descriptivo.
7. Correlaciones
mat_cor <- cor(datos[, vars_morfo], method = "spearman")
corrplot(mat_cor, method = "color", type = "upper",
addCoef.col = "black", number.cex = 0.7,
tl.col = "black", tl.srt = 45,
title = "Correlación de Spearman", mar = c(0,0,1,0))GGally::ggpairs(datos, columns = 2:5, aes(color = Especie, alpha = 0.6)) +
theme_minimal()8. Estadística multivariada
8.1 PCA (Análisis de Componentes Principales)
⚠️ Exploratorio: con n = 11 total, el PCA sirve para visualizar patrones de agrupamiento, no para inferencia confirmatoria. No se incluyen elipses de confianza por ser poco fiables con n = 4 en un grupo.
pca_res <- prcomp(datos[, vars_morfo], scale. = TRUE)
summary(pca_res)Importance of components:
PC1 PC2 PC3 PC4 PC5 PC6 PC7
Standard deviation 2.4096 1.2299 0.49983 0.43576 0.32189 0.28778 0.22873
Proportion of Variance 0.7258 0.1891 0.03123 0.02374 0.01295 0.01035 0.00654
Cumulative Proportion 0.7258 0.9149 0.94611 0.96984 0.98279 0.99315 0.99969
PC8
Standard deviation 0.05013
Proportion of Variance 0.00031
Cumulative Proportion 1.00000
fviz_pca_biplot(pca_res,
habillage = datos$Especie,
addEllipses = FALSE,
label = "var",
repel = TRUE) +
theme_minimal() +
labs(title = "PCA - Biplot morfométrico")fviz_eig(pca_res, addlabels = TRUE) +
labs(title = "Varianza explicada por componente principal")8.2 PERMANOVA (alternativa robusta a MANOVA con n bajo)
dist_euclid <- vegdist(scale(datos[, vars_morfo]), method = "euclidean")
set.seed(123)
permanova_res <- adonis2(dist_euclid ~ Especie, data = datos, permutations = 999)
permanova_resPermutation test for adonis under reduced model
Permutation: free
Number of permutations: 999
adonis2(formula = dist_euclid ~ Especie, data = datos, permutations = 999)
Df SumOfSqs R2 F Pr(>F)
Model 1 52.432 0.6554 17.118 0.006 **
Residual 9 27.568 0.3446
Total 10 80.000 1.0000
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Nota: con n = 4 en un grupo, el número de permutaciones únicas posibles es limitado, por lo que el p-valor de PERMANOVA debe interpretarse como orientativo, no como prueba dura.
8.3 Análisis Discriminante Lineal (LDA) — clasificador exploratorio
lda_res <- lda(Especie ~ ., data = datos[, c("Especie", vars_morfo)])
lda_resCall:
lda(Especie ~ ., data = datos[, c("Especie", vars_morfo)])
Prior probabilities of groups:
Tityus_paraguayensis Tityus_crypticus_sp_nov
0.6363636 0.3636364
Group means:
Total_length Prosoma_length Mesosoma_length
Tityus_paraguayensis 41.06286 5.524286 10.02571
Tityus_crypticus_sp_nov 33.05000 4.725000 7.10500
Chela_length Chela_width Metasoma_V_length
Tityus_paraguayensis 7.542857 2.132857 5.695714
Tityus_crypticus_sp_nov 7.302500 2.257500 4.542500
Metasoma_V_width Length_Telson
Tityus_paraguayensis 2.517143 4.214286
Tityus_crypticus_sp_nov 2.260000 3.477500
Coefficients of linear discriminants:
LD1
Total_length -11.981374
Prosoma_length -4.325275
Mesosoma_length 12.809145
Chela_length 17.312835
Chela_width 5.603882
Metasoma_V_length 13.095573
Metasoma_V_width 17.799225
Length_Telson -3.136275
pred_lda <- predict(lda_res)
tabla_clasif <- table(Real = datos$Especie, Predicho = pred_lda$class)
kable(tabla_clasif, caption = "Matriz de confusión (ajuste interno, NO validación externa)")| Tityus_paraguayensis | Tityus_crypticus_sp_nov | |
|---|---|---|
| Tityus_paraguayensis | 7 | 0 |
| Tityus_crypticus_sp_nov | 0 | 4 |
⚠️ Importante: esta matriz de confusión es sobre los mismos datos de entrenamiento (no hay datos suficientes para separar train/test). Una clasificación “perfecta” aquí es esperable por sobreajuste y no implica que el modelo generalice a nuevos individuos. Se reporta solo como ejercicio exploratorio de separación morfométrica, no como modelo predictivo validado.
9. Sobre “modelos predictivos”
Con n = 11 (7 vs 4), construir un modelo predictivo válido (regresión logística con partición train/test, random forest, etc.) no es metodológicamente defendible: el modelo memorizaría los datos en vez de aprender un patrón generalizable, y cualquier métrica de “accuracy” sería ilusoria.
Lo que sí es razonable y se hizo arriba: - LDA como herramienta exploratoria de separación morfológica (sección 8.3). - PERMANOVA como prueba multivariada de diferencia entre grupos (sección 8.2).
Si en el futuro amplías la serie (más individuos, quizá de otras localidades o de series tipo adicionales), ahí sí valdría la pena revisar un modelo predictivo con validación cruzada (leave-one-out, dado que con esos tamaños tampoco alcanzaría para train/test clásico).
10. Resumen ejecutivo
cat("Resumen de hallazgos:\n",
"- n por especie: paraguayensis = 7, crypticus sp. nov. = 4 (muestra pequeña).\n",
"- Variables con menor solapamiento aparente (ver boxplots y descriptivos):",
"revisar Total_length, Mesosoma_length y razones Mesosoma_Total.\n",
"- PERMANOVA y PCA sugieren separación multivariada entre especies (exploratorio).\n",
"- LDA logra separación perfecta en ajuste interno (esperable, no validación real).\n",
"- Recomendación: complementar con más individuos y caracteres cualitativos",
"para fortalecer la diagnosis.\n")Resumen de hallazgos:
- n por especie: paraguayensis = 7, crypticus sp. nov. = 4 (muestra pequeña).
- Variables con menor solapamiento aparente (ver boxplots y descriptivos): revisar Total_length, Mesosoma_length y razones Mesosoma_Total.
- PERMANOVA y PCA sugieren separación multivariada entre especies (exploratorio).
- LDA logra separación perfecta en ajuste interno (esperable, no validación real).
- Recomendación: complementar con más individuos y caracteres cualitativos para fortalecer la diagnosis.