Análisis estadístico de la presencia de aves en el bosque

Contextualización

Este informe presenta un Análisis Exploratorio de Datos (EDA) para un conjunto de registros obtenidos a partir del estudio observacional de la presencia de aves en el bosque. Se hace especial enfaísis en las zonas en las que el bosque es maduro o restaurado y apartir del recorrido de diferentes transectos por estas zonas se registraon las observaciones de aves definiendo especie en cada punto de muestreo. A partir de esta ruta se recolectan también datos ambientales. El objetivo es comprender la estructura de los datos y preparar el conjunto para un modelo de explicativo de análisis de correspondencia canónica (CCA).

Extracción, Transformación y Carga (ETL)

Los datos fueron proporcionados en un archivo de Excel, por lo que no fue pertinente realizar algún trabajo de extración o importación de datos a una fuente externa. Sin embargo, el trabajo de transformación de la tabla fue necesario.

En primera instancia, según Wickman los datos siempre deben estar en un formato tidy, es decir, cada fila debe ser una observación y cada columna una variable, esto es fundamental para trabajar en entornos de tratamiendo de datos, en este caso R. Además, algunas variables se hallaban en formatos inadecuados, por ejemplo, mezclando valores de tipo númerico con carácteres o errores de tipeo al ingresar datos. Por este motivo, dentro de Excel se realizó una primera limpieza, asegurando mantener la información, evitando errores de reemplazos o duplicaciones.

Descripción del conjunto de datos

Después de este primer tratamiento, se presenta a cotinuación una tabla con los datos principales que incluye las siguentes variables de interés:

Variable Formato Descripción
Bosque string Tipo de cobertura boscosa (Maduro o Restaurado)
Fecha YYYY-MM-DD Fecha de la observación
Hora HH:MM Hora en la que se registró la observación
Transecto integer Número de transecto donde se realizó la observación
Punto de Muestreo integer Punto específico dentro del transecto
Especie de Ave string Nombre científico de la especie observada
Familia string Familia taxonómica de la especie
Estrato usado string Estrato de vegetación utilizado por el ave (ej. Arbustivo, Herbáceo)
Altura del suelo (m) float Altura a la que se encontraba el ave desde el suelo
Altura máxima cobertura arbórea (m) float Altura máxima de la cobertura arbórea en el punto
Altura del estrato herbáceo (cm) float Altura promedio de la vegetación herbácea en el punto
Tipo de actividad string Comportamiento observado (ej. forrajeando, vocalizando)
Gremio trófico string Tipo de alimentación del ave (ej. Insectívoro, Nectarívoro)
Cobertura vegetal (%) float Porcentaje estimado de cobertura vegetal
Especie vegetal dominante string Especie vegetal más representativa del punto
Composición vegetal string Listado o descripción de especies vegetales presentes
Temperatura (°C) float Temperatura registrada en el punto de observación
Humedad relativa (%) float Porcentaje de humedad relativa
Viento string Presencia o medida del viento
Coordenadas string Coordenadas geográficas del punto de muestreo
Observaciones string Comentarios adicionales registrados por el observador

A continuación, se hace un carague de los datos para una revisión general, con el propósito de realizar un análisis descriptivo de las variables. Para esto se cargan las librerías que utilizarán durante el desarrollo del trabajo.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(skimr)
library(readxl)
library(janitor)
## Warning: package 'janitor' was built under R version 4.4.3
## 
## Adjuntando el paquete: 'janitor'
## 
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
#install.packages("vegan")
library(vegan)
## Warning: package 'vegan' was built under R version 4.4.3
## Cargando paquete requerido: permute
## Warning: package 'permute' was built under R version 4.4.3
## Cargando paquete requerido: lattice

En primer lugar, se cargan los datos del Excel tratado. Además, se adaptan los nombres de las variables, es decir, de las columnas, a un camel_case para que sea más fácil trabajar con ellas en un entorno de programación.

Adicionalmente, no toda la información es relevante para el estudio, variables como Tipo de actividad, Cobertura vegetal %, Especie vegetal, Composición vegetal, Viento, Coordenadas y Osbervaciones se eliminan, dado que no son relevantes para los alcances de este estudio. Finalmente, las variables de Transecto y Punto de muestreo a pesar de estar en formato númerico deberían figurar como factor, dado que representan un dato cualitativo ordinal.

datos = read_excel("Matriz_aves.xlsx") 

datos = datos %>%
  mutate(
    Fecha = as.Date(as.numeric(Fecha), origin = "1899-12-30"), ## Se específica el origen por Excel
    Hora = format(Hora, "%H:%M:%S")
  ) %>%
  clean_names() 
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Fecha = as.Date(as.numeric(Fecha), origin = "1899-12-30")`.
## Caused by warning in `as.Date()`:
## ! NAs introducidos por coerción
datos = datos %>% 
  select(-observaciones,
         -coordenadas, 
         -viento, 
         -composicion_vegetal, 
         -especie_vegetal, 
         -cobertura_vegetal_percent, 
         -tipo_de_actividad) %>% 
  mutate(
    transecto = as.character(transecto), 
    punto_de_muestreo = as.character(punto_de_muestreo)
  )

datos
## # A tibble: 161 × 14
##    bosque fecha      hora     transecto punto_de_muestreo especie_de_ave familia
##    <chr>  <date>     <chr>    <chr>     <chr>             <chr>          <chr>  
##  1 Maduro 2024-12-14 08:00:00 1         1                 Amazilia sauc… Trochi…
##  2 Maduro 2024-12-14 08:00:00 1         1                 Atalotriccus … Tyrann…
##  3 Maduro 2024-12-14 08:00:00 1         1                 Atalotriccus … Tyrann…
##  4 Maduro 2024-12-14 08:00:00 1         1                 Atalotriccus … Tyrann…
##  5 Maduro 2024-12-14 08:00:00 1         1                 Atalotriccus … Tyrann…
##  6 Maduro 2024-12-14 08:00:00 1         1                 Phaethornis a… Trochi…
##  7 Maduro 2024-12-14 10:22:00 1         3                 Atalotriccus … Tyrann…
##  8 Maduro 2024-12-14 10:22:00 1         3                 Atalotriccus … Tyrann…
##  9 Maduro 2024-12-14 10:22:00 1         3                 Atalotriccus … Tyrann…
## 10 Maduro 2024-12-14 10:22:00 1         3                 Formicivora g… Thamno…
## # ℹ 151 more rows
## # ℹ 7 more variables: estrato_usado <chr>, altura_del_suelo_m <dbl>,
## #   altura_maxima_covertura_arborea_m <dbl>,
## #   altura_del_estrato_herbacio_cm <dbl>, gremio_trofico <chr>,
## #   temperatura_c <dbl>, humedad_percent <dbl>

Análisis de las variables

En las siguientes tablas se muestra un resumen de la información relevante de cada variable. Para desarrollar una explicación posterior más detallada.

datos %>% 
  skim()
Data summary
Name Piped data
Number of rows 161
Number of columns 14
_______________________
Column type frequency:
character 8
Date 1
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
bosque 0 1 6 11 0 2 0
hora 0 1 8 8 0 36 0
transecto 0 1 1 1 0 5 0
punto_de_muestreo 0 1 1 1 0 5 0
especie_de_ave 0 1 8 26 0 49 0
familia 0 1 7 14 0 25 0
estrato_usado 0 1 7 16 0 7 0
gremio_trofico 0 1 9 25 0 10 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
fecha 4 0.98 2024-12-14 2025-02-11 2024-12-28 10

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
altura_del_suelo_m 0 1.00 6.79 9.26 0.00 2.0 4.0 8.00 58.0 ▇▁▁▁▁
altura_maxima_covertura_arborea_m 0 1.00 20.33 16.36 6.00 9.0 12.0 30.00 58.0 ▇▁▂▁▂
altura_del_estrato_herbacio_cm 0 1.00 73.75 49.15 0.00 29.0 70.0 110.00 195.0 ▇▆▆▅▁
temperatura_c 9 0.94 24.14 2.50 18.90 23.0 23.8 24.92 30.9 ▂▅▇▁▁
humedad_percent 99 0.39 69.96 26.51 6.95 62.4 80.0 84.50 98.6 ▁▂▁▅▇
datos %>% 
  filter(bosque == "Restarurado") %>% 
  skim()
Data summary
Name Piped data
Number of rows 51
Number of columns 14
_______________________
Column type frequency:
character 8
Date 1
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
bosque 0 1 11 11 0 1 0
hora 0 1 8 8 0 15 0
transecto 0 1 1 1 0 3 0
punto_de_muestreo 0 1 1 1 0 4 0
especie_de_ave 0 1 8 24 0 25 0
familia 0 1 7 14 0 14 0
estrato_usado 0 1 8 16 0 6 0
gremio_trofico 0 1 9 25 0 8 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
fecha 0 1 2025-01-11 2025-02-08 2025-01-12 3

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
altura_del_suelo_m 0 1.0 7.92 9.91 0.00 1.80 3.50 9.00 30.0 ▇▁▁▁▂
altura_maxima_covertura_arborea_m 0 1.0 17.27 11.42 7.00 7.00 12.00 30.00 38.0 ▇▁▁▃▁
altura_del_estrato_herbacio_cm 0 1.0 78.27 39.66 26.00 47.00 84.00 85.00 195.0 ▆▇▃▁▁
temperatura_c 0 1.0 23.59 1.11 20.40 23.00 23.80 24.00 25.0 ▁▁▃▇▂
humedad_percent 46 0.1 7.20 0.56 6.95 6.95 6.95 6.95 8.2 ▇▁▁▁▂
datos %>% 
  filter(bosque == "Maduro") %>% 
  skim()
Data summary
Name Piped data
Number of rows 110
Number of columns 14
_______________________
Column type frequency:
character 8
Date 1
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
bosque 0 1 6 6 0 1 0
hora 0 1 8 8 0 24 0
transecto 0 1 1 1 0 5 0
punto_de_muestreo 0 1 1 1 0 5 0
especie_de_ave 0 1 8 26 0 41 0
familia 0 1 7 14 0 23 0
estrato_usado 0 1 7 16 0 7 0
gremio_trofico 0 1 9 25 0 9 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
fecha 4 0.96 2024-12-14 2025-02-11 2024-12-22 9

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
altura_del_suelo_m 0 1.00 6.26 8.95 0.0 2.0 4.3 7.95 58.0 ▇▁▁▁▁
altura_maxima_covertura_arborea_m 0 1.00 21.75 18.07 6.0 10.0 14.0 34.00 58.0 ▇▁▁▁▂
altura_del_estrato_herbacio_cm 0 1.00 71.65 53.01 0.0 18.0 50.0 120.00 150.0 ▇▅▂▃▆
temperatura_c 9 0.92 24.42 2.93 18.9 22.6 24.1 25.70 30.9 ▂▇▇▂▂
humedad_percent 53 0.52 75.47 19.57 27.4 69.8 80.4 84.60 98.6 ▂▁▃▇▅

El conjunto de datos utilizado para este análisis contiene 161 observaciones distribuidas en 14 variables. Estas variables comprenden distintos tipos de información: 8 variables de tipo carácter, 5 variables numéricas y 1 variable de tipo fecha. Esta diversidad de formatos refleja la complejidad ecológica del estudio, integrando aspectos taxonómicos, estructurales y microclimáticos asociados a la observación de aves en bosques maduros y restaurados. A continuación, se presenta un análisis descriptivo detallado de cada una de las variables registradas.

Variables cualitativas

Fecha

La variable fecha representa el día específico en que se llevó a cabo cada observación. Presenta una tasa de completitud del 97.5%, con apenas cuatro registros ausentes. El rango de fechas abarca desde el 14 de diciembre de 2024 hasta el 11 de febrero de 2025. Esta distribución temporal sugiere un periodo de muestreo continuo y concentrado en la estación seca del año, lo que resulta relevante al momento de interpretar patrones ecológicos dentro del marco estacional.

Bosque

La variable bosque clasifica los registros de observación en función del tipo de ecosistema, diferenciando entre bosque maduro y bosque restaurado. No presenta valores faltantes (100% de completitud) y contiene dos niveles distintos.

datos %>%
  group_by(bosque) %>%
  summarise(
    conteo = n(),
    proporcion = round(n() / nrow(datos), 3)*100
  )
## # A tibble: 2 × 3
##   bosque      conteo proporcion
##   <chr>        <int>      <dbl>
## 1 Maduro         110       68.3
## 2 Restarurado     51       31.7
datos %>% 
  ggplot(aes(y=bosque, fill = bosque))+
  geom_bar()+
  scale_fill_brewer(palette = "Pastel2")

Hora

Indica el momento del día en el que fue registrada cada observación. Se encuentra completa y abarca un muestreo que se halla distribuido a lo largo de la mañana, principalmnete entre las 06:00 y 12:30.

Especie de ave

La variable especie_de_ave recoge el nombre científico de la especie registrada durante la observación. Con 49 especies únicas y sin valores faltantes.

datos %>% 
  group_by(especie_de_ave) %>%
  summarise(
    conteo = n(),
    proporcion = round(n() / nrow(datos), 3)*100
  ) %>% 
  arrange(-conteo)
## # A tibble: 49 × 3
##    especie_de_ave          conteo proporcion
##    <chr>                    <int>      <dbl>
##  1 Troglodytes aedon           13        8.1
##  2 Atalotriccus pilaris        11        6.8
##  3 Formicivora grisea          11        6.8
##  4 Leptotila verreauxi          8        5  
##  5 Protonotaria citrea          8        5  
##  6 Ortalis garrula              7        4.3
##  7 Sin aves                     7        4.3
##  8 Cyanocorax affinis           6        3.7
##  9 Inezia caudata               6        3.7
## 10 Phaethornis anthophilus      6        3.7
## # ℹ 39 more rows
datos %>%
  filter(especie_de_ave != "Sin aves") %>%
  count(especie_de_ave, sort = TRUE) %>%
  slice_max(n, n = 16) %>%
  inner_join(datos, by = "especie_de_ave") %>%  # Mantiene solo las especies más comunes
  ggplot(aes(y = fct_infreq(especie_de_ave), fill = bosque)) +
  geom_bar()+
  scale_fill_brewer(palette = "Pastel2")

Familia

La variable familia corresponde a la familia taxonómica de cada especie registrada. Contiene 25 niveles distintos y está completa.

datos %>% 
  filter(familia != "Sin aves") %>% 
  group_by(familia) %>%
  summarise(
    conteo = n(),
    proporcion = round(n() / nrow(datos), 3)*100
  ) %>% 
  arrange(-conteo)
## # A tibble: 24 × 3
##    familia        conteo proporcion
##    <chr>           <int>      <dbl>
##  1 Tyrannidae         26       16.1
##  2 Thamnophilidae     23       14.3
##  3 Troglodytidae      21       13  
##  4 Columbidae         13        8.1
##  5 Trochilidae        11        6.8
##  6 Parulidae           8        5  
##  7 Cracidae            7        4.3
##  8 Thochilidae         7        4.3
##  9 Corvidae            6        3.7
## 10 Accipitridae        5        3.1
## # ℹ 14 more rows
datos %>%
  filter(familia != "Sin aves") %>%
  count(familia, sort = TRUE) %>%
  slice_max(n, n = 16) %>%
  inner_join(datos, by = "familia") %>%  # Mantiene solo las especies más comunes
  ggplot(aes(y = fct_infreq(familia), fill = bosque)) +
  geom_bar()+
  scale_fill_brewer(palette = "Pastel2")

Estrato usado

La variable estrato_usado identifica el nivel de la vegetación donde se observó a la especie (por ejemplo, herbáceo, arbustivo, subarbóreo). Con 7 categorías distintas y sin valores perdidos, esta variable permite estudiar la verticalidad en el uso del hábitat por parte de la avifauna, un aspecto esencial para evaluar la estructura del bosque y su funcionalidad.

datos %>% 
  filter(estrato_usado != "sin estrato") %>% 
  ggplot(aes(y = fct_infreq(estrato_usado), fill= bosque))+
  geom_bar()+
  scale_fill_brewer(palette = "Pastel2")

datos %>%
  filter(especie_de_ave != "Sin aves") %>%
  count(especie_de_ave, sort = TRUE) %>%
  slice_max(n, n = 20) %>%
  inner_join(datos, by = "especie_de_ave") %>%  # Mantiene solo las especies más comunes
  ggplot(aes(y = fct_infreq(especie_de_ave), fill = estrato_usado)) +
  geom_bar()+
  scale_fill_brewer(palette = "Pastel1")

Gremio trófico

La variable gremio_trofico clasifica a las especies según su dieta dominante (por ejemplo, insectívoro, nectarívoro, frugívoro). Tiene una tasa de complitut total y cuenta con 10 categorías distintas.

datos %>% 
  ggplot(aes(y = fct_infreq(gremio_trofico), fill= bosque))+
  geom_bar()+
  scale_fill_brewer(palette = "Pastel2")

datos %>%
  filter(especie_de_ave != "Sin aves") %>%
  count(especie_de_ave, sort = TRUE) %>%
  slice_max(n, n = 15) %>%
  inner_join(datos, by = "especie_de_ave") %>%  # Mantiene solo las especies más comunes
  ggplot(aes(y = fct_infreq(especie_de_ave), fill = gremio_trofico)) +
  geom_bar()+
  scale_fill_brewer(palette = "Pastel1")

Transecto

La variable transecto representa el número asignado a cada línea de muestreo. No presenta datos faltantes y se distribuye entre 1 y 5. Esta variable es útil para el control espacial del muestreo.

Punto de muestreo

La variable punto_de_muestreo indica el número del punto dentro de cada transecto donde se realizó la observación. Se disponen hasta un máximo de 5 puntos de muestreo por transecto y sin valores ausentes. Junto con transecto, permite establecer la unidad espacial mínima de muestreo y es útil para análisis espaciales finos o para evaluar independencia de las observaciones.

2.2 Variables cuantitativas

Altura del suelo (m)

La variable altura_del_suelo_m representa la altura a la que se observó el ave desde el nivel del suelo. Tiene un rango de 0 a 58 m, con una media de 6.79 m y una alta dispersión (SD = 9.26). La amplia variabilidad sugiere que las observaciones incluyen desde especies rasantes hasta aves que se posan en el dosel superior.

datos %>%
  ggplot(aes(x = altura_del_suelo_m, fill = bosque)) +
  geom_histogram(bins = 15, color = "black") +
  facet_wrap(~ bosque) +
  scale_fill_brewer(palette = "Pastel2")

datos %>% 
  ggplot(aes(y = bosque, x = altura_del_suelo_m, fill = bosque))+
  geom_violin()+
  scale_fill_brewer(palette = "Pastel2")+
  geom_boxplot(width = .1, fill = "black", outlier.colour = NA) +
  stat_summary(fun.y = median, geom = "point", fill = "white", shape = 21, size = 2.5)
## Warning: The `fun.y` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
## ℹ Please use the `fun` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

datos %>%
  ggplot(aes(x = fct_reorder(familia, altura_del_suelo_m, .fun = mean),
             y = altura_del_suelo_m)) +
  geom_boxplot() +
  theme(
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Altura máxima de cobertura arbórea (m)

La altura_maxima_covertura_arborea_m refleja la altura del dosel arbóreo en el sitio de muestreo. Su media es de 20.33 m con un rango entre 6 y 58 m, lo que sugiere una buena heterogeneidad estructural vertical. Esta variable puede actuar como un proxy de madurez forestal y es relevante al evaluar complejidad del hábitat.

datos %>%
  ggplot(aes(x = altura_maxima_covertura_arborea_m, fill = bosque)) +
  geom_histogram(bins = 10, color = "black") +
  facet_wrap(~ bosque) +
  scale_fill_brewer(palette = "Pastel2")

datos %>% 
  ggplot(aes(y = bosque, x = altura_maxima_covertura_arborea_m, fill = bosque))+
  geom_violin()+
  scale_fill_brewer(palette = "Pastel2")+
  geom_boxplot(width = .1, fill = "black", outlier.colour = NA) +
  stat_summary(fun.y = median, geom = "point", fill = "white", shape = 21, size = 2.5)

datos %>%
  ggplot(aes(x = fct_reorder(familia, altura_maxima_covertura_arborea_m, .fun = mean),
             y = altura_maxima_covertura_arborea_m)) +
  geom_boxplot() +
  theme(
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Altura del estrato herbáceo (cm)

La altura_del_estrato_herbacio_cm mide la altura de la vegetación herbácea en el punto de observación. Su promedio es de 73.75 cm, con un rango desde 0 hasta 195 cm, evidenciando variaciones notables en la cobertura basal del bosque. Esta información es útil para entender microhábitats de especies rasantes o que nidifican en el suelo.

datos %>%
  ggplot(aes(x = altura_del_estrato_herbacio_cm, fill = bosque)) +
  geom_histogram(bins = 10, color = "black") +
  facet_wrap(~ bosque) +
  scale_fill_brewer(palette = "Pastel2")

datos %>% 
  ggplot(aes(y = bosque, x = altura_del_estrato_herbacio_cm, fill = bosque))+
  geom_violin()+
  scale_fill_brewer(palette = "Pastel2")+
  geom_boxplot(width = .1, fill = "black", outlier.colour = NA) +
  stat_summary(fun.y = median, geom = "point", fill = "white", shape = 21, size = 2.5)

datos %>%
  ggplot(aes(x = fct_reorder(familia, altura_del_estrato_herbacio_cm, .fun = mean),
             y = altura_del_estrato_herbacio_cm)) +
  geom_boxplot() +
  theme(
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Temperatura (°C)

En este caso, se registra la temperatura del aire en el momento de la observación. Esta presenta un 5.6% de valores faltantes (9 en total), con una media de 24.14 °C y un rango entre 18.9 y 30.9 °C. Estos valores son consistentes con un clima seco tropical. Sin embargo, esta variación de la temperatura esta fuertemnete influenciada con la hora del día a la que se realizó el muestreo.

datos %>%
  ggplot(aes(x = temperatura_c, fill = bosque)) +
  geom_histogram(bins = 15, color = "black", na.rm = TRUE) +
  facet_wrap(~ bosque) +
  scale_fill_brewer(palette = "Pastel2")

datos %>% 
  filter(!is.na(temperatura_c)) %>%
  ggplot(aes(y = bosque, x = temperatura_c, fill = bosque))+
  geom_violin(na.rm = TRUE)+
  scale_fill_brewer(palette = "Pastel2")+
  geom_boxplot(width = .1, fill = "black", outlier.colour = NA) +
  stat_summary(fun.y = median, geom = "point", fill = "white", shape = 21, size = 2.5)

datos %>%
  filter(!is.na(temperatura_c)) %>%
  ggplot(aes(x = fct_reorder(familia, temperatura_c, .fun = mean),
             y = temperatura_c)) +
  geom_boxplot() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Humedad relativa (%)

La variable humedad_percent tiene una tasa de completitud muy baja (38.5%), con 99 valores ausentes. A pesar de esto, los datos disponibles muestran un rango entre 6.95% y 98.6%, con una media de 69.96%.

Debido a la alta cantidad de valores perdidos y la estrucutra de los datos se imposibilita la posibilidad de emplear una técnica de imputación, por lo tanto se optó por descartar esta variable en su uso para modelos explicativos.

datos %>%
  ggplot(aes(x = humedad_percent, fill = bosque)) +
  geom_histogram(bins = 15, color = "black", na.rm = TRUE) +
  facet_wrap(~ bosque) +
  scale_fill_brewer(palette = "Pastel2")

Correlación entre variables

library(GGally)
## Warning: package 'GGally' was built under R version 4.4.3
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
datos %>%
  select(temperatura_c, humedad_percent,
         altura_del_suelo_m, 
         altura_maxima_covertura_arborea_m, 
         altura_del_estrato_herbacio_cm) %>%
  drop_na() %>%
  ggpairs(
    upper = list(continuous = wrap("cor", size = 3)),
    lower = list(continuous = wrap("smooth", alpha = 0.3)),
    diag = list(continuous = wrap("densityDiag"))
  ) 

En primer lugar, es pertinente comentar queque la correlación en este caso no implica dependencia o causalidad, entre las variables, especialmente porque el diseño del estudio es observacional y no experimental. Dicho esto, la matriz de correlación muestra relaciones entre las variables microclimáticas y estructurales del bosque. La temperatura del aire presenta una correlación positiva moderada con la altura del estrato herbáceo (r = 0.42), así como con la altura desde el suelo (r = 0.30) y la altura máxima de cobertura arbórea (r = 0.27), en el contexto de este estudio no podría interpretarse que áreas con mayor desarrollo vertical tienden a registrar temperaturas ligeramente más elevadas, en realidad, la temperatura en este caso está más bien influenciada por el momento de muestreo y dado que la mayoría de las observaciones fueron hechas en el bosque madurado existe una correlación positiva entre estas variables. Por el contrario, la humedad relativa sí muestra una coherencia física pues se relaciona negativamente de forma débil con la temperatura (r = –0.14), sin embargo, debido a la tasa de incompletitud de datos en la humedad relativa este análisis carece de valor real para el estudio. Por otro lado, se observa una correlación considerable entre la altura máxima de la cobertura arbórea y la altura del estrato herbáceo (r = 0.56).

datos %>%
  select(bosque, temperatura_c, humedad_percent,
         altura_del_suelo_m, 
         altura_maxima_covertura_arborea_m, 
         altura_del_estrato_herbacio_cm) %>%
  drop_na() %>%
  suppressMessages() %>%
  suppressWarnings() %>%
  ggpairs(
    mapping = aes(color = bosque),  # Color por tipo de bosque
    upper = list(continuous = wrap("cor", size = 3)),
    lower = list(continuous = wrap("smooth", alpha = 0.3)),
    diag = list(continuous = wrap("densityDiag"))
  )+
  scale_fill_brewer(palette = "Pastel2")

Un análisis más profundo requiere relacionar las variables según el tipo de bosque en el que habitan las aves.

En el bosque maduro, las correlaciones entre variables ambientales y estructurales muestran patrones consistentes con una vegetación verticalmente compleja. Se observa una correlación positiva moderada entre la temperatura del aire y la altura máxima de la cobertura arbórea (r = 0.33), así como con la altura del suelo (r = 0.27) y especialmente con la altura del estrato herbáceo (r = 0.65).

datos %>%
  filter(!is.na(temperatura_c)) %>%
  mutate(
    hora_continua = hour(hms(hora)) + minute(hms(hora)) / 60
  ) %>%
  ggplot(aes(x = hora_continua, y = temperatura_c, color = familia)) +
  geom_point(alpha = 0.7, size = 2) 

A su vez, la altura del estrato herbáceo muestra relaciones positivas claras con las demás variables estructurales, destacando su papel como indicador de complejidad vegetal (r = 0.59 con la altura del dosel y r = 0.45 con la altura del suelo). Por el contrario, la humedad relativa no presenta correlaciones significativas con ninguna variable estructural (todas cercanas a cero), y se relaciona de forma inversa con la temperatura (r = –0.53), un patrón esperado por la interacción entre temperatura y retención de humedad.

En el bosque restaurado, la baja densidad de registros representa un problema significativo para el estudio bivariado o multivariado, lo cual indica un sesgo por bajo número de observaciones o una fuerte colinealidad en las mediciones. Por ejemplo, la temperatura y la humedad están perfectamente correlacionadas lo que sugiere que en este conjunto específico se midió de forma simultánea bajo condiciones homogéneas. Algunas correlaciones atípicamente perfectas exhiben un comportamiento irreal en el bosque y están influenciadas por tamaño muestral reducido y valores redundantes.

Análisis de correspondencia canónica (CAA)

El Análisis de Correspondencia Canónica (CCA) es una técnica multivariada de ordenación que se utiliza para explorar y visualizar la relación entre variables biológicas (como abundancia o presencia de especies) y variables ambientales (como temperatura, humedad, óxigeno disuelto, entre otras). En un CCA las dimensiones de ordenación están restringidas por un conjunto de variables explicativas.

Un CCA combina la ordinación (arreglando las especies y el sitio a lo lagro del eje) con una regresión (evaluando la relación entre la especie y el medio). En términos ecológicos, el CCA permite identificar cómo varía la composición de especies en respuesta a gradientes ambientales. Cada eje de ordenación representa una combinación lineal de las variables ambientales, y las especies y sitios se posicionan en ese espacio según su afinidad con dichos gradientes.

A diferencia de otros métodos, un CCA asume que una especie tiene una respuesta unimodal a los gradientes ambientales, lo cual implica que la abundacia de una especie depende de sus condiciones ambientales.

matriz_especies = datos %>%
  filter(especie_de_ave != "Sin aves") %>%
  count(bosque, especie_de_ave) %>%
  pivot_wider(names_from = especie_de_ave,
              values_from = n,
              values_fill = 0) %>%
  column_to_rownames(var = "bosque")

head(matriz_especies)
##             Amazilia saucerrottei Amazilia tzacatl Anthracothorax nigricollis
## Maduro                          1                2                          2
## Restarurado                     0                1                          0
##             Atalotriccus pilaris Bubo virginianus Cantorchilus leucotis
## Maduro                         9                1                     2
## Restarurado                    2                0                     0
##             Chlorostilbon gibsoni Chondrohierax unicantus Chrysuronia goudoti
## Maduro                          1                       2                   2
## Restarurado                     1                       0                   0
##             Coereba flaveola Cyanocorax affinis Daptrius chimachima
## Maduro                     2                  6                   1
## Restarurado                0                  0                   0
##             Elaenia chiriquensis Eupsittula pertinax Formicivora grisea
## Maduro                         2                   2                  4
## Restarurado                    0                   0                  7
##             Formicivora intermedia Galbula ruficauda Geranospiza caerulescens
## Maduro                           2                 1                        1
## Restarurado                      0                 0                        0
##             Icterus galbula Inezia caudata Leptotila verreauxi
## Maduro                    1              4                   5
## Restarurado               0              2                   3
##             Momotus subrufescens Myiarchus. Sp Nonnula frontalis
## Maduro                         1             4                 1
## Restarurado                    1             1                 0
##             Patagioenas cayennensis Phaethornis anthophilus Piaya cayana
## Maduro                            4                       5            1
## Restarurado                       1                       1            2
##             Picumnus cinnamomeus Pintangus sulfuratus Piranga rubra
## Maduro                         2                    1             1
## Restarurado                    1                    0             0
##             Protonotaria citrea Ramphastos sulfuratus Ruporni magnirostris
## Maduro                        2                     2                    1
## Restarurado                   6                     0                    0
##             Sakesphorus canadensis Synallaxis candei Thamnophilus atrinucha
## Maduro                           1                 1                      3
## Restarurado                      0                 0                      1
##             Thamnophilus melanonotus Thraupis episcopus Thryophilus rufalbus
## Maduro                             2                  2                    4
## Restarurado                        3                  0                    2
##             Troglodytes aedon Chrysolampis mosquitus Dendroplex picus
## Maduro                     13                      0                0
## Restarurado                 0                      1                2
##             Dryocopus lineatus Hylophilus flavipes Lepidopyga goudoti
## Maduro                       0                   0                  0
## Restarurado                  1                   1                  1
##             Ortalis garrula Rostrhamus sociabilis Tolmomyias sulphurescens
## Maduro                    0                     0                        0
## Restarurado               7                     1                        1
matriz_ambiental = datos %>%
  group_by(bosque) %>%
  summarise(
    temperatura_c = mean(temperatura_c, na.rm = TRUE),
    ## humedad_percent = mean(humedad_percent, na.rm = TRUE), se descarta la humedad por falta de información
    altura_suelo = mean(altura_del_suelo_m, na.rm = TRUE),
    ## altura_herbacea = mean(altura_del_estrato_herbacio_cm, na.rm = TRUE),
    ## altura_dosel = mean(altura_maxima_covertura_arborea_m, na.rm = TRUE)
  ) %>%
  column_to_rownames(var = "bosque")

head(matriz_ambiental)
##             temperatura_c altura_suelo
## Maduro           24.41584     6.263636
## Restarurado      23.59412     7.921373
modelo_cca <- cca(matriz_especies ~ ., data = matriz_ambiental)
## 
## Some constraints or conditions were aliased because they were redundant. This
## can happen if terms are linearly dependent (collinear): 'altura_suelo'
## 
## The model is overfitted with no unconstrained (residual) component
summary(modelo_cca)
## 
## Call:
## cca(formula = matriz_especies ~ temperatura_c + altura_suelo,      data = matriz_ambiental) 
## 
## Partitioning of scaled Chi-square:
##               Inertia Proportion
## Total          0.4786          1
## Constrained    0.4786          1
## Unconstrained  0.0000          0
## 
## Eigenvalues, and their contribution to the scaled Chi-square 
## 
## Importance of components:
##                         CCA1
## Eigenvalue            0.4786
## Proportion Explained  1.0000
## Cumulative Proportion 1.0000
## 
## Accumulated constrained eigenvalues
## Importance of components:
##                         CCA1
## Eigenvalue            0.4786
## Proportion Explained  1.0000
## Cumulative Proportion 1.0000

Los resultados presentes en el CCA a partir del modelo creado y almacenados en la variable modelo_cca advierte que “Some constraints or conditions were aliased because they were redundant. This can happen if terms are linearly dependent (collinear).” Esto significa que las variables ambientales están correlacionadas entre sí significativamente. Además, presentan colinealidad, por lo cual el modelo no puede estimar sus efectos de forma independiente.

Adicionalmente, el método de CCA no logra explicar nada porque no hay nada que pueda explicar realmente, ya que debido a la falta de diferencias en las características de los bosques y su relación con las variables ambientales sólo existe un único componente. Dado que el componente no restringido es nulo, no queda nada de variabilidad residual para estimar. A su vez, el componente restringido explica el 100% de la inercia (0.4786).

Esto ocurre porque el modelo está sobredimensionado respecto a la cantidad de observaciones disponibles (en este caso, solo dos sitios: bosque maduro y bosque restaurado), por lo que el CCA no puede separar adecuadamente la variabilidad de las especies más allá de lo que ya está explicito en estas variables ambientales.

Por lo tanto, se concluye que el CCA no es un modelo adecuado para análizar la relación entre las variables ambientales y los sitios en que habitan las especies.

Análisis de correspondencia simple (CA)

El Análisis de Correspondencia (CA) es una técnica multivariada de ordenación que permite explorar y visualizar la estructura de tablas de contingencia o matrices de conteo (por ejemplo, abundancia de especies en diferentes sitios). Su objetivo es representar gráficamente la relación entre las filas (sitios) y las columnas (especies) de forma que se puedan identificar patrones de asociación.

Por lo tanto, con este CA se utiliza para analizar la composición de comunidades biológicas representadas en este caso por la variable especie_ave sin necesidad de incorporar variables ambientales. La técnica reduce la dimensionalidad de los datos, proyectando los sitios y las especies en un espacio de pocos ejes, donde la proximidad entre puntos refleja similitud en su perfil composicional.

modelo_ca <- cca(matriz_especies)
summary(modelo_ca)
## 
## Call:
## cca(X = matriz_especies) 
## 
## Partitioning of scaled Chi-square:
##               Inertia Proportion
## Total          0.4786          1
## Unconstrained  0.4786          1
## 
## Eigenvalues, and their contribution to the scaled Chi-square 
## 
## Importance of components:
##                          CA1
## Eigenvalue            0.4786
## Proportion Explained  1.0000
## Cumulative Proportion 1.0000

El Análisis de Correspondencia (CA) aplicado a la matriz de especies por tipo de bosque generó un único eje de ordenación (CA1), que explica el 100% de la inercia del sistema. Esto es redundante y no proporciona nueva información. Sin embargo, es un resultado es esperado, dado que solo se consideraron dos sitios (bosque maduro y bosque restaurado), lo cual limita el número de dimensiones que puede capturar el análisis. En este contexto, el eje CA1 representa la mayor fuente de variación en la composición de especies entre ambos tipos de bosque, y permite concluir que según el modelo no hay una diferencia significativa entre la presencia de las especies de aves y el tipo de bosque.

Conclusión

Tanto el CA como el CAA al ser técnicas de análisis multivariado proporcionan resultados más adecuados cuando se trabaja con un mayor número de sitios, y variables ambientales con diferencias importantes, permitiendo explorar patrones más complejos de distribución de las aves en diferentes medios y la influencia que ejercen las condiciones ambientales sobre el habitad de las especies.

Por lo tanto, para ambos casos CA y CCA no se presentan gráficas, ya que, al hacer plot(modelo_ca) no aparece nada porque solo hay un eje disponible (CA1), y el gráfico intenta por defecto mostrar un plano, por lo menos, bidimensional (CA1 vs CA2). Como no hay un segundo eje, no se puede graficar.

Análisis de diversidad

Índice de Shannon

Este índice mide la diversidad teniendo en cuenta tanto la riqueza (número de especies) como la equidad (uniformidad en la abundancia). Es sensible a las especies raras, por lo que valores más altos indican no solo muchas especies, sino también una distribución más uniforme entre ellas.

\[ H' = -\sum_{i=1}^{S} p_i \cdot \ln(p_i) \]

Donde \(p_i\) es la proporción de individuos de la especie \(i\), y \(S\) es el número total de especies.

Índice de Simpson

El índice de Simpson representa la probabilidad de que dos individuos seleccionados al azar pertenezcan a la misma especie. A diferencia del de Shannon, es más sensible a las especies dominantes. Valores cercanos a 1 indican baja diversidad (pues existe una especie que domina), mientras que valores bajos indican mayor diversidad.

\[ D = \sum_{i=1}^{S} p_i^2 \]

Índice Inverso de Simpson

Es el inverso del índice de Simpson. Se interpreta de forma más directa: un valor mayor representa una comunidad más diversa. Es útil cuando se quiere que el valor del índice aumente con la diversidad.

\[ \frac{1}{D} = \frac{1}{\sum_{i=1}^{S} p_i^2} \]

Alpha de Fisher

Este índice se basa en un modelo teórico de distribución logarítmica de abundancias. Es especialmente útil cuando se comparan comunidades con diferentes tamaños de muestra. Fisher’s alpha es independiente del número total de individuos y es apropiado para comparar diversidad entre sitios con tamaños desiguales.Se estima a partir del ajuste de una distribución logarítmica de la forma:

\[ S = \alpha \cdot \ln \left(1 + \frac{N}{\alpha} \right) \]

Donde, $ S $ es el número de especies, $N $ es el número total de individuos, \(\alpha\) fisher.alpha es el parámetro estimado por ajuste.

tibble(
  bosque = rownames(matriz_especies),
  riqueza = rowSums(matriz_especies > 0), # número de especies
  shannon = diversity(matriz_especies, index = "shannon"),
  simpson = diversity(matriz_especies, index = "simpson"),
  invsimpson = diversity(matriz_especies, index = "invsimpson"),
  fisher = fisher.alpha(matriz_especies)
)
## # A tibble: 2 × 6
##   bosque      riqueza shannon simpson invsimpson fisher
##   <chr>         <dbl>   <dbl>   <dbl>      <dbl>  <dbl>
## 1 Maduro           40    3.39   0.954       21.8   23.8
## 2 Restarurado      24    2.88   0.926       13.4   18.1

El análisis de diversidad muestra diferencias consistentes entre el bosque maduro y el bosque restaurado. En primer lugar, el índice de riqueza indica que el bosque maduro alberga 40 especies distintas, mientras que el restaurado contiene solo 24, lo cual refleja una mayor heterogeneidad específica en el primero. Este patrón se confirma con el índice de Shannon (3.39 en el bosque maduro vs. 2.88 en el restaurado), lo que sugiere que en el bosque maduro no solo hay más especies, sino también una distribución de abundancias más equitativa entre ellas. El índice de Simpson también es mayor en el bosque maduro (0.954), indicando una menor probabilidad de dominancia por una sola especie. En contraposición, el valor es más bajo en el bosque restaurado (0.926) sugiere una comunidad menos diversa y con mayor dominancia. Por otra parte, el índice inverso de Simpson, que facilita la interpretación directa de la diversidad (donde valores más altos indican mayor diversidad), refuerza esta diferencia: 23.80 en el bosque maduro frente a 13.44 en el restaurado. Finalmente, el índice alpha de Fisher también fue superior en el bosque maduro, mostrando resultados de 18.13 en el restaurado vs. 23.79 en el maduro, lo que confirma que la diversidad específica en este tipo de bosque es más elevada incluso al controlar por el número total de individuos.