Por: Raymond L. Tremblay

NotaQué es este capítulo

Este capítulo es una guía práctica de uso del paquete Rage, organizada por la pregunta de investigación que cada métrica responde —no por el orden alfabético de las funciones. Asume que ya tiene un objeto CompadreDB filtrado (capítulo anterior) o una matriz construida a mano (capítulos 5–8). Para cada función mostramos: la pregunta biológica, el código mínimo para responderla, y una interpretación de los resultados que tenga sentido en el contexto de orquídeas.

Tip¿Qué métrica para qué pregunta? — Guía rápida
Si quiere responder… Use la métrica Función de Rage
¿Cuánto vive un individuo en promedio? Esperanza de vida media life_expect_mean()
¿Hay individuos longevos? ¿Y la varianza de longevidad? Esperanza de vida + varianza life_expect_var()
¿Cada cuánto se reemplaza la población? Tiempo generacional gen_time()
¿A qué edad los individuos llegan a reproducirse por primera vez? Edad a la primera reproducción mature_age()
¿Qué proporción de individuos llegan a reproducirse? Probabilidad de madurez mature_prob()
¿Cuántos descendientes deja un individuo a lo largo de su vida? Tasa neta de reproducción (\(R_0\)) net_repro_rate()
¿La especie es iterópara o semélpara? Entropía de Demetrius entropy_d()
¿Qué tan dispersa es la mortalidad a lo largo de la vida? Entropía de Keyfitz entropy_k()
¿Qué tan rápido crece o decae la población? Tasa asintótica \(\lambda\) popbio::lambda() (no Rage)
¿Cómo se distribuyen los individuos entre etapas en estado estable? Distribución estable de etapas popbio::stable.stage()
¿Qué transición tiene el mayor efecto sobre \(\lambda\)? Sensibilidad / elasticidad popbio::elasticity()
AdvertenciaTrampas comunes con Rage
  • Las funciones de Rage requieren las submatrices (matU, matF, matC), no la matriz A completa. Use siempre matU(x), matF(x), matC(x) —no matA(x).
  • Devuelven NA silenciosamente sobre matrices degeneradas (filas vacías, columnas que suman cero, dimensiones incompatibles). Envuelva las llamadas en tryCatch() cuando aplique sobre listas grandes (ver ejemplos abajo).
  • El argumento start define la etapa inicial desde la que se calcula la métrica. Por defecto es start = 1L (la primera etapa, normalmente plántula). Para una métrica desde el adulto, use el índice o nombre de la etapa adulta.
  • life_expect_mean() asume que el individuo “entra” al modelo en la etapa start. Si su MPP comienza con una etapa cripto (banco de semillas, latencia), la esperanza de vida puede estar inflada.
  • gen_time() y net_repro_rate() requieren que matF no sea idénticamente cero. Si la fecundidad sólo aparece en matC (clonal), use matC en vez de matF o redefina su pregunta.

17.0.0.1 Librerías de R requeridas para el siguiente módulo

Código
library(Rcompadre) # Paquete para trabajar con la base de datos de COMPADRE y COMADRE
library(tidyverse) # Paquete para activar múltiples paquetes
library(readxl)
library(broom)
library(ggdist)
library(distributional)
library(leaflet)
library(Rage) # función para calcular el largo de vida esperada entre otras
library(car)
library(popdemo)
library(skimr)
library(flextable) # Paquete para formatear tablas

El presente capítulo examina una selección de funciones contenidas en el paquete Rage, diseñado para facilitar el análisis de datos provenientes de las bases de datos COMPADRE y COMADRE. Estos repositorios públicos reúnen información sobre la dinámica poblacional de plantas (COMPADRE) y animales (COMADRE), estructurada en matrices de transición por estados o edades (MPP). La librería Rage ofrece herramientas analíticas que permiten estimar parámetros demográficos clave, tales como la esperanza de vida, la edad de inicio de la reproducción, la entropía poblacional y la tasa de crecimiento, entre otros. A lo largo del capítulo, se ilustran algunas de estas funciones y se demuestra su aplicación en el estudio de la dinámica poblacional de especies de orquídeas.


17.1 Cargar la base de COMPADRE

Para los detalles de cómo obtener la base de datos, ver el capítulo anterior. Aquí simplemente cargamos el snapshot incluido con el libro:

Código
compadre <- readRDS("data/COMPADRE_2026.rds")
Tip

Rage versus Rcompadre. El paquete Rcompadre (capítulo anterior) se enfoca en acceder y filtrar la base; el paquete Rage se enfoca en calcular métricas demográficas a partir de las matrices ya filtradas. La división de tareas es intencional: cargar y validar es un paso, calcular esperanza de vida o entropía es otro. Ambos paquetes pertenecen a la misma familia y comparten convenciones de nombres (e.g., matU(), matF()).


17.1.1 Filtrar para la familia Orchidaceae

Para filtrar únicamente las especies pertenecientes a la familia Orchidaceae en la base de datos COMPADRE, usamos la función filter() del paquete dplyr:

Código
Orquideas = compadre %>%
  filter(Family %in% c("Orchidaceae")) # Extraer las orquídeas de la base de datos.

# Orquideas es un objeto CompadreDB
head(cdb_metadata(Orquideas), n = 3) |>
  flextable() |> ft_wide()

MatrixID

SpeciesAuthor

SpeciesAccepted

CommonName

Kingdom

Phylum

Class

Order

Family

Genus

Species

Infraspecies

InfraspeciesType

OrganismType

DicotMonoc

AngioGymno

Authors

Journal

SourceType

OtherType

YearPublication

DOI_ISBN

AdditionalSource

StudyDuration

StudyStart

StudyEnd

ProjectionInterval

MatrixCriteriaSize

MatrixCriteriaOntogeny

MatrixCriteriaAge

MatrixPopulation

NumberPopulations

Lat

Lon

Altitude

Country

Continent

Ecoregion

StudiedSex

MatrixComposite

MatrixSeasonal

MatrixTreatment

MatrixCaptivity

MatrixStartYear

MatrixStartSeason

MatrixStartMonth

MatrixEndYear

MatrixEndSeason

MatrixEndMonth

CensusType

MatrixSplit

MatrixFec

Observations

MatrixDimension

SurvivalIssue

_Database

_PopulationStatus

_PublicationStatus

238,285

Caladenia_amonea

Caladenia amonea

Plantae

Tracheophyta

Liliopsida

Asparagales

Orchidaceae

Caladenia

amonea

Herbaceous perennial

Monocot

Angiosperm

Raymond L. Tremblay; Pérez; Larcombe; Brown; Quarmby; Bickerton; French; Bould

Aust J Bot

Journal Article

2009

10.1071/BT08167

12

1996

2007

1

No

Yes

No

North-eastern Melbourne, Vic

1

AUS

Oceania

TBM

A

Mean

No

Unmanipulated

W

1996

Summer

8

2007

Autumn

9

Divided

Locations of surveyed areas are kept vague to reduce the likelihood of unauthorised disturbance of the populations

3

1

COMPADRE

Released

Released

238,286

Caladenia_argocalla

Caladenia argocalla

Plantae

Tracheophyta

Liliopsida

Asparagales

Orchidaceae

Caladenia

argocalla

Herbaceous perennial

Monocot

Angiosperm

Raymond L. Tremblay; Pérez; Larcombe; Brown; Quarmby; Bickerton; French; Bould

Aust J Bot

Journal Article

2009

10.1071/BT08167

12

1996

2007

1

No

Yes

No

Adelaide Hills and Clare Valley, SA

1

AUS

Oceania

TBM

A

Mean

No

Unmanipulated

W

2003

Autumn

9

2007

Autumn

10

Divided

No

Locations of surveyed areas are kept vague to reduce the likelihood of unauthorised disturbance of the populations

3

1

COMPADRE

Released

Released

238,287

Caladenia_clavigera

Caladenia clavigera

Plantae

Tracheophyta

Liliopsida

Asparagales

Orchidaceae

Caladenia

clavigera

Herbaceous perennial

Monocot

Angiosperm

Raymond L. Tremblay; Pérez; Larcombe; Brown; Quarmby; Bickerton; French; Bould

Aust J Bot

Journal Article

2009

10.1071/BT08167

12

1996

2007

1

No

Yes

No

North-eastern Melbourne, Vic

1

AUS

Oceania

TBM

A

Mean

No

Unmanipulated

W

1997

Autumn

9

2007

Autumn

10

Divided

Locations of surveyed areas are kept vague to reduce the likelihood of unauthorised disturbance of the populations

3

1

COMPADRE

Released

Released


17.2 ¿Cuántos estudios únicos?

En este bloque de código se construye un nuevo conjunto de datos, SPECIES_O, que resume información clave sobre los estudios incluidos en la base de datos de orquídeas. Se seleccionan variables relevantes como el año de inicio y finalización del estudio (StudyStart, StudyEnd), el nombre científico aceptado de la especie (SpeciesAccepted), el año de publicación (YearPublication), los autores (Authors), el identificador del artículo (DOI_ISBN), el tipo de organismo (OrganismType), y el identificador de población (MatrixPopulation), junto con la matriz de proyección (mat).

Luego, se agrupan los datos por especie, año de publicación, tipo de organismo y periodo del estudio, y se calcula el número de poblaciones únicas muestreadas por especie mediante length(unique(MatrixPopulation)). El resultado se ordena alfabéticamente por especie y se normalizan los valores de los años como variables numéricas. Finalmente, se recodifica la variable OrganismType para traducir los términos originales del inglés al español: “Epiphyte” se convierte en “Epífita” y “Herbaceous perennial” en “Terrestre”. Se eliminan los registros con valores faltantes en los años de inicio o finalización del estudio.

Este resumen permite visualizar de forma clara cuántas poblaciones fueron muestreadas por especie, en qué periodo se realizaron los estudios, y qué tipo de orquídea fue analizada, lo que facilita comparaciones entre especies y estudios.

Código
#names(Orquideas) Los nombres de las variables
SPECIES_O = Orquideas %>%
  select(
    StudyStart,
    StudyEnd,
    SpeciesAccepted,
    YearPublication,
    Authors,
    DOI_ISBN,
    OrganismType,
    MatrixPopulation,
    mat
  ) %>%
  group_by(
    SpeciesAccepted,
    YearPublication,
    OrganismType,
    StudyStart,
    StudyEnd
  ) %>%
  summarize(n_populations = length(unique(MatrixPopulation))) %>%
  arrange(SpeciesAccepted) %>%
  mutate(StudyStart = as.numeric(StudyStart)) %>%
  mutate(StudyEnd = as.numeric(StudyEnd)) %>%
  mutate(OrganismType_RC=fct_recode(OrganismType,
                             "Epífita"="Epiphyte",
                             "Terrestre"="Herbaceous perennial")) |> 
  drop_na(StudyStart, StudyEnd) |> 
  ungroup()
  

flextable(head(SPECIES_O))

SpeciesAccepted

YearPublication

OrganismType

StudyStart

StudyEnd

n_populations

OrganismType_RC

Aspasia principissa

2006

Epiphyte

1,997

2,004

1

Epífita

Brassavola cucullata

2020

Epiphyte

2,009

2,014

3

Epífita

Broughtonia cubensis

2021

Epiphyte

2,006

2,019

3

Epífita

Caladenia amonea

2009

Herbaceous perennial

1,996

2,007

1

Terrestre

Caladenia argocalla

2009

Herbaceous perennial

1,996

2,007

1

Terrestre

Caladenia clavigera

2009

Herbaceous perennial

1,996

2,007

1

Terrestre

Código
#write_csv(SPECIES_O, "DATA/Species_O.csv")

17.2.1 Determinar cuántas poblaciones fueron muestreadas por especie

¿Cuál es la frecuencia de poblaciones por especie en la base de datos?

  • La mayoría de las especies fueron estudiadas en una sola población.

  • Sin embargo, hay casos en los que se muestrearon hasta 18 poblaciones distintas para una misma especie.

Este gráfico permite observar claramente la concentración de estudios en pocas poblaciones, así como los casos excepcionales con mayor cobertura. Esto puede reflejar diferencias en el diseño de los estudios, disponibilidad de datos o interés ecológico particular en ciertas especies.

Código
as.data.frame(table(SPECIES_O$n_populations)) |> 
  ggplot(aes(Var1, Freq))+
  geom_bar(stat="identity",aes(fill="lightblue"))+
  rlt_style_fill() +
  ylab("Frecuencia")+
  xlab("Cantidad de Poblaciones \n en el estudio")+
  theme(legend.position = "none")


17.2.2 La cantidad de poblaciones por especies en la base de datos de COMPADRE.

La cantidad de poblaciones muestreadas por especie en la base de datos de COMPADRE varía considerablemente. Aunque la mayoría de las especies están representadas por una sola población, existen casos en los que se han registrado hasta 20 poblaciones distintas para una misma especie. Estas poblaciones pueden provenir de diferentes publicaciones científicas o representar datos recolectados en distintos momentos o con distintos objetivos dentro de una misma población. Por ejemplo, los datos de Lepanthes rupestris provienen de dos estudios independientes (Tremblay & Ackerman, 2001; Tremblay & McCarthy, 2014). En el primero, se utilizaron matrices poblacionales para estimar el tamaño efectivo de las poblaciones (Ne), mientras que en el segundo se emplearon los mismos datos para desarrollar un enfoque bayesiano que permite estimar los elementos de las matrices de transición, especialmente útil cuando se dispone de pocos datos por población o periodo. Este enfoque aprovecha la información conjunta de todas las poblaciones para generar estimaciones más robustas y biológicamente realistas.


17.2.3 ¿Cuán largos fueron los estudios?

La duración de los estudios en la base de datos de orquídeas de COMPADRE varía considerablemente. Aunque muchos estudios abarcan solo unos pocos años —el mínimo requerido para calcular una matriz de transición poblacional es de dos periodos—, también existen investigaciones que se extienden por lapsos más prolongados. Algunos estudios, como los realizados por Tremblay con Lepanthes rupestris, incluyen muestreos mensuales, mientras que otros se basan en observaciones anuales. Esta diversidad en la temporalidad refleja tanto los objetivos específicos de cada investigación como las estrategias metodológicas empleadas.

La siguiente visualización muestra cómo varía la duración de los estudios según el tipo de orquídea, diferenciando entre especies epífitas y terrestres:

Código
SPECIES_O$SpeciesAccepted <- fct_reorder(
  SPECIES_O$SpeciesAccepted,
  SPECIES_O$StudyStart,
  .desc = FALSE
)

ggplot(SPECIES_O, aes(SpeciesAccepted, ymin = StudyStart, ymax = StudyEnd, color = OrganismType_RC)) +
  geom_linerange() +
  coord_flip() +
  theme(legend.position.inside = c(0.2, 0.8)) +
  ylab("") +
  xlab("") +
  rlt_style_colour() +
  theme(
    axis.text.x = element_text(
      color = "grey20",
      size = 9,
      angle = 90,
      hjust = .5,
      vjust = .5,
      face = "plain"
    ),
    axis.text.y = element_text(
      color = "grey20",
      size = 7,
      angle = 0,
      hjust = 1,
      vjust = 0,
      face = "plain"
    ),
    axis.title.x = element_text(
      color = "grey20",
      size = 12,
      angle = 0,
      hjust = .5,
      vjust = 0,
      face = "plain"
    ),
    axis.title.y = element_text(
      color = "grey20",
      size = 12,
      angle = 90,
      hjust = .5,
      vjust = .5,
      face = "plain"
    )
  )+
  theme(legend.position = c(0.2,0.8),
        legend.title = element_blank())+
  theme(axis.text.y = element_text(size = 5))+
  scale_y_continuous(n.breaks = 12)

Código
#ggsave("images/Lenght_survey.png")

17.2.4 Tiempo de duración de las investigaciones.

La siguiente figura muestra la duración de los estudios realizados sobre orquídeas epífitas y terrestres. Según los datos extraídos de la base de datos COMPADRE, la mayoría de las investigaciones tuvieron una duración relativamente corta, especialmente en el caso de las especies epífitas. Sin embargo, también se registran estudios que se extendieron por más de 20 años, lo que evidencia un compromiso a largo plazo en algunos casos para entender mejor la dinámica poblacional de estas plantas.

Código
Orquideas = Orquideas %>%
  mutate(StudyDuration = as.numeric(StudyDuration),
    OrganismType_RC = fct_recode(
      OrganismType,
      "Epífita" = "Epiphyte",
      "Terrestre" = "Herbaceous perennial"
    )
  )

#table(Orquideas$StudyDuration)
#table(Orquideas$OrganismType)

ggplot(Orquideas, aes(StudyDuration, fill = OrganismType_RC)) +
  geom_histogram(colour = "white") +
  facet_wrap(~OrganismType_RC) +
  theme(legend.position = "none") +
  xlab("Duración de los estudios") +
  ylab("Frecuencia") +
  rlt_style_fill() +
  scale_x_continuous(n.breaks = 10)

Código
#ggsave("Duración_Epi_Ter.pdf")

ggsave("images/Duración_Epi_Ter.png")


17.2.5 Cálculo del Valor Propio Dominante (λ) en Matrices Ergódicas e Irreducibles

A partir del conjunto de matrices previamente filtradas por cumplir con las condiciones de ergodicidad e irreducibilidad, se procede al cálculo del valor propio dominante (\(\lambda\)), el cual representa la tasa de crecimiento poblacional asintótica en modelos matriciales.

Para ello, se emplea la función eigs del paquete popdemo, que permite obtener los valores propios de una matriz. Esta función se aplica a cada matriz seleccionada mediante sapply, generando una lista de valores de (\(\lambda\)) almacenados en el objeto lambdaVals. Cada entrada en esta lista corresponde al valor propio dominante de una matriz matA incluida en el conjunto de datos.

Posteriormente, se utiliza la función summary para obtener una descripción estadística de los valores de (\(\lambda\)), y la función hist para visualizar su distribución, lo que permite evaluar la variabilidad en las tasas de crecimiento poblacional entre las distintas especies o poblaciones representadas.

17.2.5.1 Matrices ergódicas e irreductibles

Código
Compadre_flagged <- cdb_flag(Orquideas)

Mat_erg_irred <- subset(
  Compadre_flagged,
  check_NA_A == FALSE & check_irreducible == TRUE & check_ergodic == TRUE
) # para evaluar si las matrices son ergódicas e irreducibles al mismo tiempo

head(cdb_metadata(Mat_erg_irred), n=2) |>
  flextable() |> ft_wide()

MatrixID

SpeciesAuthor

SpeciesAccepted

CommonName

Kingdom

Phylum

Class

Order

Family

Genus

Species

Infraspecies

InfraspeciesType

OrganismType

DicotMonoc

AngioGymno

Authors

Journal

SourceType

OtherType

YearPublication

DOI_ISBN

AdditionalSource

StudyDuration

StudyStart

StudyEnd

ProjectionInterval

MatrixCriteriaSize

MatrixCriteriaOntogeny

MatrixCriteriaAge

MatrixPopulation

NumberPopulations

Lat

Lon

Altitude

Country

Continent

Ecoregion

StudiedSex

MatrixComposite

MatrixSeasonal

MatrixTreatment

MatrixCaptivity

MatrixStartYear

MatrixStartSeason

MatrixStartMonth

MatrixEndYear

MatrixEndSeason

MatrixEndMonth

CensusType

MatrixSplit

MatrixFec

Observations

MatrixDimension

SurvivalIssue

_Database

_PopulationStatus

_PublicationStatus

OrganismType_RC

check_NA_A

check_NA_U

check_NA_F

check_NA_C

check_zero_U

check_zero_F

check_zero_C

check_zero_U_colsum

check_singular_U

check_component_sum

check_ergodic

check_irreducible

check_primitive

check_surv_gte_1

238,285

Caladenia_amonea

Caladenia amonea

Plantae

Tracheophyta

Liliopsida

Asparagales

Orchidaceae

Caladenia

amonea

Herbaceous perennial

Monocot

Angiosperm

Raymond L. Tremblay; Pérez; Larcombe; Brown; Quarmby; Bickerton; French; Bould

Aust J Bot

Journal Article

2009

10.1071/BT08167

12

1996

2007

1

No

Yes

No

North-eastern Melbourne, Vic

1

AUS

Oceania

TBM

A

Mean

No

Unmanipulated

W

1996

Summer

8

2007

Autumn

9

Divided

Locations of surveyed areas are kept vague to reduce the likelihood of unauthorised disturbance of the populations

3

1

COMPADRE

Released

Released

Terrestre

false

false

false

false

false

true

true

false

false

true

true

true

true

false

238,286

Caladenia_argocalla

Caladenia argocalla

Plantae

Tracheophyta

Liliopsida

Asparagales

Orchidaceae

Caladenia

argocalla

Herbaceous perennial

Monocot

Angiosperm

Raymond L. Tremblay; Pérez; Larcombe; Brown; Quarmby; Bickerton; French; Bould

Aust J Bot

Journal Article

2009

10.1071/BT08167

12

1996

2007

1

No

Yes

No

Adelaide Hills and Clare Valley, SA

1

AUS

Oceania

TBM

A

Mean

No

Unmanipulated

W

2003

Autumn

9

2007

Autumn

10

Divided

No

Locations of surveyed areas are kept vague to reduce the likelihood of unauthorised disturbance of the populations

3

1

COMPADRE

Released

Released

Terrestre

false

false

false

false

false

true

true

false

false

true

true

true

true

false

Código
lambdaVals_list <- sapply(matA(Mat_erg_irred), popdemo::eigs, what = "lambda") 

lambdaVals=as_tibble(lambdaVals_list)

tidy(lambdaVals) |> flextable()
Error in `seq.default()`:
! wrong sign in 'by' argument
Código
ggplot(lambdaVals, aes(value))+
  geom_histogram(aes(fill="lightblue"), colour="white")+
  rlt_style_fill()+
  xlab("Lambda")+
  ylab("Frecuencia")+
  scale_x_continuous(n.breaks = 10)+
  theme(legend.position = "none")

Una metodología alternativa para calcular los valores propios dominantes (\(\lambda\)) de las matrices de transición poblacional consiste en utilizar la función map_dbl de la librería purrr. Esta función permite aplicar una operación a cada elemento de una lista, devolviendo un vector numérico de igual longitud. En este contexto, se aplica una función de cálculo de \(\lambda\) a cada matriz de transición (matA), obteniendo así un valor de \(\lambda\) por matriz. Esta estrategia resulta eficiente para el procesamiento simultáneo de múltiples matrices dentro de un flujo de trabajo reproducible en R.

Código
## con el paquete popdemo
lambdaVals1 <- map_dbl(
  matA(Mat_erg_irred),
  ~ popdemo::eigs(.x, what = "lambda")
)

## O puede calcular lambda con el paquete popbio, que evita algunos mensajes de advertencia

lambdaVals2 <- map_dbl(matA(Mat_erg_irred), ~ popbio::lambda(.x))

17.3 Demografía con Rage

Hasta este punto hemos usado Rcompadre para acceder y filtrar matrices, y popbio/popdemo para calcular \(\lambda\). El paquete Rage complementa este flujo con funciones que derivan estadísticos demográficos directamente de las matrices U, F y C. A continuación mostramos tres ejemplos sobre el subconjunto filtrado en Mat_erg_irred.

TipRecordatorio sobre las submatrices

Las funciones de Rage requieren que las matrices estén descompuestas en sus partes (U = supervivencia/crecimiento, F = fecundidad sexual, C = crecimiento clonal). Por eso se extraen con matU(), matF() y matC() en lugar de usar la matriz completa A.

17.3.1 Esperanza de vida — ¿cuánto vive un individuo?

Pregunta biológica. Dado que un individuo sobrevive su etapa inicial (plántula), ¿cuánto tiempo vive en promedio? life_expect_mean() lo calcula a partir de la matriz U, modelándola como una cadena de Markov absorbente donde “muerte” es el estado absorbente.

Código
esperanza_vida <- map_dbl(
  matU(Mat_erg_irred),
  ~ tryCatch(Rage::life_expect_mean(.x, start = 1L),
             error = function(e) NA_real_)
)

summary(esperanza_vida)
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max.       NA's 
-15787.092      1.841      6.714    -11.664     17.912    635.403         34 
TipInterpretación

Una esperanza de vida alta (> 30 pasos de tiempo) indica una especie longeva con mortalidad adulta baja —típico de orquídeas epífitas adultas establecidas. Valores bajos (< 5 pasos de tiempo) sugieren mortalidad juvenil dominante, lo que es esperable cuando start = 1L corresponde a plántulas con supervivencia baja. Si el valor parece irrealista, verifique: (1) que start apunte a la etapa correcta, y (2) que la matriz U no contenga valores de supervivencia perfecta (ver el capítulo sobre datos sin sentido biológico).

17.3.2 Tiempo generacional — ¿cada cuánto se reemplaza la población?

Pregunta biológica. ¿Cuántos años (o pasos de tiempo) pasan entre que un individuo nace y produce su descendencia “promedio”? Es la unidad fundamental para comparar la velocidad evolutiva entre especies. gen_time() combina la matriz U (supervivencia/crecimiento) con la matriz F (reproducción).

Código
tiempo_gen <- map2_dbl(
  matU(Mat_erg_irred),
  matF(Mat_erg_irred),
  ~ tryCatch(Rage::gen_time(.x, .y),
             error = function(e) NA_real_)
)

summary(tiempo_gen)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   -Inf   13.82   36.34     NaN  124.90     Inf      41 
TipInterpretación

Un tiempo generacional alto (> 10) indica especies “lentas”, longevas, con generaciones traslapadas —el patrón típico de orquídeas epífitas perennes. Tiempos bajos (< 2) sugieren especies “rápidas” con ciclos cortos —raras en orquídeas, comunes en hierbas anuales. Las orquídeas terrestres templadas y las epífitas tropicales suelen ubicarse en el rango 5–25, dependiendo de la longevidad observada. Comparar tiempos generacionales entre poblaciones de la misma especie en hábitats distintos es una forma poderosa de detectar diferenciación demográfica local.

17.3.3 Edad de primera reproducción — ¿cuándo arranca la reproducción?

Pregunta biológica. ¿A qué edad llega un individuo, en promedio, a su primera etapa reproductiva? Es un componente clave de las estrategias de historia de vida —la diferencia entre “rápido y arriesgado” y “lento y seguro”. mature_age() integra a través de la matriz U partiendo de la etapa start.

Código
edad_madurez <- map2_dbl(
  matU(Mat_erg_irred),
  matF(Mat_erg_irred),
  ~ tryCatch(Rage::mature_age(.x, .y, start = 1L),
             error = function(e) NA_real_)
)

summary(edad_madurez)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  1.000   4.908   7.306  11.322  10.075 111.000      85 
TipInterpretación

En orquídeas terrestres templadas se han documentado edades de primera reproducción de 5–15 años; en epífitas tropicales el rango puede ser similar o mayor. Comparar mature_age con life_expect_mean da el “esfuerzo prereproductivo” relativo: si un individuo gasta el 40% de su vida esperada antes de reproducirse, la mortalidad juvenil tiene un peso desproporcionado en la dinámica poblacional —y por tanto en cualquier estrategia de conservación.

AdvertenciaCómo defender estos números frente a una revisión crítica

Las tres métricas anteriores son robustas matemáticamente pero sensibles a tres decisiones del modelador: 1. Etapa inicial (start). ¿Está reportando esperanza de vida desde la semilla, la plántula, o el adulto recién reclutado? Especifique siempre. 2. Calidad de la matriz U. Si colSums(matU) == 1 para alguna columna (supervivencia perfecta —ver capítulo sobre datos sin sentido biológico), las tres métricas se inflan artificialmente. La esperanza de vida puede tender a infinito. 3. Reproducción clonal vs. sexual. Si la mayoría de la reproducción ocurre en matC (clonal) y matF está casi vacía, gen_time() y mature_age() no representan lo que el lector espera. Reporte ambas matrices y, si la clonalidad domina, considere usar matU + matC en lugar de matU + matF.


17.4 Variación en el crecimiento poblacional entre especies epífitas y terrestres

En esta sección se seleccionan las especies clasificadas como epífitas y terrestres, agrupándolas en objetos distintos que contienen todas las poblaciones muestreadas correspondientes. Esta separación permite evaluar comparativamente la variación en las tasas de crecimiento poblacional entre ambos grupos funcionales, facilitando el análisis de patrones ecológicos y demográficos asociados a sus respectivos hábitos de vida.

AdvertenciaCuidado con la pseudoreplicación

Cada matriz de COMPADRE corresponde a una combinación específica de población, año y especie. Una sola especie puede aportar muchas matrices, de modo que comparar directamente los \(\lambda\) entre grupos (epífitas vs. terrestres) sin tener en cuenta esta estructura jerárquica subestima la varianza real y puede inflar las diferencias aparentes. Para inferencias formales conviene usar modelos mixtos con la especie (y, idealmente, la población) como efecto aleatorio.

Código
epifitas = Orquideas %>%
  filter(OrganismType == "Epiphyte")

terrestres = Orquideas %>%
  filter(OrganismType == "Herbaceous perennial")
Código
Compadre_flagged_epif <- cdb_flag(epifitas)

x_epif <- subset(
  Compadre_flagged_epif,
  check_NA_A == FALSE & check_ergodic == TRUE
)

#sapply(matA(x_epi), popdemo::eigs, what="lambda")

lambda_epif <- map_dbl(matA(x_epif), ~ popdemo::eigs(.x, what = "lambda"))

#Or with popbio, which avoids some warning messages…

Compadre_flagged_terrestres <- cdb_flag(terrestres)

x_terr <- subset(
  Compadre_flagged_terrestres,
  check_NA_A == FALSE & check_ergodic == TRUE
)

lambda_terr <- map_dbl(matA(x_terr), ~ popdemo::eigs(.x, what = "lambda"))

17.4.1 Evaluación de Tendencias Centrales y Dispersión en Especies Terrestres y Epífitas

Mediante el uso de la función summary, se analizaron las medidas de tendencia central y dispersión de los valores propios de lambda correspondientes a especies terrestres y epífitas. Los resultados indican que las especies terrestres presentan una mayor dispersión en los valores de lambda en comparación con las especies epífitas. Aunque los promedios difieren ligeramente entre ambos grupos, las medianas resultaron ser similares, lo que sugiere patrones demográficos comparables en términos de centralidad, pero con variabilidad distinta en su comportamiento poblacional.

Código
library(flextable)

# Calcular resúmenes
epif_summary <- summary(lambda_epif)
terr_summary <- summary(lambda_terr)

# Unire los resúmenes en un solo data frame
combined_df <- rbind(
  Epífita = epif_summary,
  Terrestre = terr_summary
)

# Convertir a data frame y añadir columna de hábitat
combined_df <- as.data.frame(combined_df)
combined_df$Habit <- rownames(combined_df)

# Reordenar columnas
combined_df <- combined_df[, c("Habit", names(epif_summary))]

# Crear la tabla con flextable
flextable(combined_df)

Habit

Min.

1st Qu.

Median

Mean

3rd Qu.

Max.

Epífita

0.3887968

0.9690608

0.9950628

0.9776130

1.004671

1.359231

Terrestre

0.4088863

0.9295530

0.9992454

0.9988654

1.043194

1.776031

Para visualizar los datos en una figura de ggplot2, hay que convertir estas filas en un data frame y añadir una columna con el tipo de hábitat, renombrar la columna lambda y unir los dos data frames en uno solo.

Código
df_Lamb_epif = as.data.frame(lambda_epif)
df_Lamb_terr = as.data.frame(lambda_terr)

Crear una columna con el tipo de hábitat y renombrar la columna lambda

Código
df_Lamb_epi = df_Lamb_epif %>%
  add_column(Habit_Type = "Epífitas") %>%
  rename(lambda = lambda_epif)

df_Lamb_terr = as.data.frame(lambda_terr)
df_Lamb_terr = df_Lamb_terr %>%
  add_column(Habit_Type = "Terrestre") %>%
  rename(lambda = lambda_terr)

Unir los dos data.frame en uno solo

Código
ALL_Lambdas = rbind(df_Lamb_epi, df_Lamb_terr) # unir los dos data frame en uno

Visualizar el crecimiento poblacional por tipo de hábitat

Código
ggplot(ALL_Lambdas, aes(lambda, fill = Habit_Type)) +
  geom_histogram(colour = "white") +
  facet_wrap(~Habit_Type) +
  rlt_style_fill()+
  scale_x_continuous(n.breaks = 8)+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  ylab("Frecuencia")

Código
# ggsave("images/Terr_Epi_lambda.png")

17.5 Estimación del crecimiento promedio y evaluación de diferencias significativas

Para evaluar si existen diferencias significativas en los valores propios de lambda entre especies epífitas y terrestres, se emplea un modelo lineal utilizando la función lm. En este análisis, la variable Habit_Type se utiliza como predictor del valor propio dominante (\(\lambda\)), lo que permite estimar el efecto del tipo de hábitat sobre la tasa de crecimiento poblacional. Los resultados del modelo indican que las especies epífitas tienden a presentar valores de lambda más bajos en comparación con las especies terrestres. Para obtener los coeficientes específicos de cada grupo, se ajusta un segundo modelo excluyendo el intercepto mediante la inclusión de -1 en la fórmula. Esta parametrización permite calcular directamente el promedio de lambda para cada grupo funcional, facilitando la comparación entre ellos.

Nota¿Modelar \(\lambda\) o \(\log(\lambda)\)?

Los valores de \(\lambda\) son estrictamente positivos y su escala es multiplicativa: \(\lambda = 1\) separa crecimiento de declive y los desvíos por arriba (1.2) y por abajo (0.8) no son simétricos. Por eso muchos demógrafos prefieren modelar \(\log(\lambda)\) (o \(r = \log(\lambda)\)), que sí es simétrico alrededor de cero, suele cumplir mejor los supuestos de normalidad, y conecta directamente con la teoría de crecimiento estocástico (ver el capítulo de simulaciones). Para el ajuste mostrado aquí podrías usar lm(log(lambda) ~ Habit_Type, data = ALL_Lambdas).

Código
model_lambda = lm(lambda ~ Habit_Type, data = ALL_Lambdas)
#summary(model_lambda)

model_lambda_epi_terr = lm(lambda ~ Habit_Type-1, data = ALL_Lambdas)
#summary(model_lambda_epi_terr)

tidy_results= tidy(model_lambda_epi_terr)

flextable(tidy_results)

term

estimate

std.error

statistic

p.value

Habit_TypeEpífitas

0.9776130

0.007781499

125.633

0

Habit_TypeTerrestre

0.9988654

0.007387240

135.215

0


17.5.1 Visualización de las distribuciones de los lambda’s

Para representar gráficamente las distribuciones de los coeficientes estimados en el modelo lineal, se emplean las librerías ggdist y distributional, utilizando la función stat_halfeye. Esta función permite visualizar la forma y dispersión de las distribuciones de los parámetros, proporcionando una representación intuitiva de la incertidumbre asociada a cada estimación. Es importante destacar que stat_halfeye requiere especificar explícitamente la distribución de los datos; en este análisis, se asume que los valores propios de lambda (\(\lambda\)) siguen una distribución normal. La información utilizada para esta visualización proviene del modelo ajustado previamente (model_lambda), lo que permite comparar directamente los coeficientes entre grupos funcionales como epífitas y terrestres.

Código
model_lambda_epi_terr %>%
  tidy() %>%
  ggplot(aes(y = term)) +
  stat_halfeye(
    aes(
      xdist = dist_student_t(
        df = df.residual(model_lambda_epi_terr),
        mu = estimate,
        sigma = std.error
      )
    )
  )

La gráfica anterior puede ocultar la dispersión de los datos, especialmente cuando hay sesgos. Para abordar esto, se pueden añadir los datos originales a la figura. En este caso, se ha incorporado un símbolo de barra | por cada valor de lambda en la parte inferior de la gráfica. Al observar esta nueva visualización, se nota que la dispersión varía significativamente si se compara la representación basada en el promedio y el error estándar con la distribución real de los datos, representada por los |. Esta figura permite apreciar mejor tanto la dispersión como la distribución de los datos. En comparación con la gráfica anterior, esta ofrece una perspectiva más completa, destacando los valores que se alejan del centro de la distribución.

Código
ALL_Lambdas %>%
  expand(Habit_Type) %>%
  augment(model_lambda, newdata = ., se_fit = TRUE) %>%
  ggplot(aes(y = Habit_Type, colour = Habit_Type)) +
  stat_halfeye(
    aes(
      xdist = dist_student_t(
        df = df.residual(model_lambda),
        mu = .fitted,
        sigma = .se.fit
      )
    ),
    scale = .5
  ) +
  geom_point(
    aes(x = lambda),
    data = ALL_Lambdas,
    pch = "|",
    size = 2,
    position = position_nudge(y = -.15)
  )+
  theme(legend.position = c(0.1, 0.8)) +
  rlt_style_colour()+
  ylab("")


17.6 Mapa de distribución de los estudios.

La lista presentada corresponde a los datos extraídos de la base de datos COMPADRE, complementados con información obtenida directamente de los artículos científicos, con el objetivo de construir un mapa que muestre dónde se han realizado estudios de dinámica poblacional.

Lamentablemente, COMPADRE aún carece de muchos datos y detalles importantes que deberían incorporarse a su base. En esta sección, se realizó una búsqueda específica de estudios sobre orquídeas dentro de COMPADRE, extrayendo las coordenadas de latitud y longitud directamente de los artículos originales.

En los casos en que no se encontraron coordenadas exactas, pero sí se identificó el país o región del estudio, se utilizó Google Maps para estimar las coordenadas aproximadas del sitio de muestreo. Cuando no fue posible obtener ninguna información sobre la localización del estudio, esos casos fueron excluidos del mapa.

Agradezco a Diana Molina Ozuma por su valiosa colaboración en la búsqueda de las coordenadas de los sitios de estudio.

Código
Orchid_data_DOI_Diana_3a <- read_excel("data/Orchid_data_DOI_Diana_3a.xlsx")
Código
Lat_Long = Orchid_data_DOI_Diana_3a %>%
  select(SpeciesAccepted, Lon, Lat, OrganismType) |>
  distinct(SpeciesAccepted, Lon, Lat, OrganismType)

#write_csv(Lat_Long, "data/Orchid_data_DOI_Diana_3a.csv")

17.6.1 Visualización de distribución geoespacial

Para representar la distribución geográfica de las orquídeas registradas en la base de datos COMPADRE, se utilizó el paquete ggplot2. En esta visualización, se emplea la función borders, que incorpora los contornos de los países al mapa. Esta función se basa en el paquete maps, el cual proporciona los datos geográficos necesarios para delinear los límites nacionales, permitiendo contextualizar espacialmente los puntos de muestreo.

Código
ggplot2::ggplot(Lat_Long, aes(Lon, Lat, colour = OrganismType)) +
  borders(database = "world", fill = "grey80", colour = NA) +
  geom_point(size = 1.0, alpha = 0.5)+
  theme(legend.position = c(0.15,0.2))+
  rlt_style_colour()
Error in `map_data()`:
! The package "maps" is required for `map_data()`.
Código
#ggsave("orchid_map.jpg")

17.7 Mapa de distribución interactivo con Leaflet

Se utilizó el paquete Leaflet para crear un mapa interactivo que muestra los sitios de muestreo de las especies de orquídeas estudiadas en campo. Este enfoque permite explorar visualmente la distribución geográfica de las poblaciones incluidas en los estudios.

El mapa revela una marcada disparidad en los sitios de muestreo entre los dos tipos de orquídeas. Las poblaciones marcadas en rojo corresponden a especies epífitas, mientras que las azules representan especies terrestres. Se observa que las especies terrestres están principalmente distribuidas en Europa y América del Norte, con escasa representación en Asia y ninguna en África. Por otro lado, las especies epífitas se concentran en el Caribe y América Central (especialmente México), sin presencia en África, Asia ni Australia.

ImportanteSesgo geográfico de COMPADRE

La distribución que se ve en el mapa no refleja la diversidad real de las orquídeas en el mundo, sino la distribución geográfica del esfuerzo de investigación demográfica. Regiones con altísima diversidad de orquídeas (Borneo, Nueva Guinea, los Andes, el África tropical) están casi ausentes de la base de datos. Cualquier conclusión global sobre patrones demográficos debe interpretarse con esta limitación en mente: estamos describiendo dónde se ha estudiado, no dónde habitan las orquídeas.

Además, el mapa es interactivo y permite hacer zoom para examinar áreas específicas con mayor detalle. Presiona sobre los puntos para obtener información adicional sobre el nombre científico de la especie muestreada en este sitio.

Código
PointUsePalette <- leaflet::colorFactor(
  palette = c("#009392", "#CF597E"),
  domain = c("Epiphyte", "Herbaceous perennial")
) # para asignar los colores a los factores (clase de Vida)

Orchid_map = leaflet(Lat_Long) %>% # los datos
  addTiles() %>%
  addCircleMarkers(
    lng = ~Lon, # la longitud
    lat = ~Lat, # la latitud
    radius = 2, # el tamaño del punto
    color = ~ PointUsePalette(OrganismType), # Para colorear los puntos por el tipo clase de vida
    popup = ~ paste0("<I>", SpeciesAccepted, "</I>") # para poner los nombres científicos en itálicos
  )

Orchid_map
Código
# htmltools::save_html(Orchid_map, file = "Orchid_map.html") # El script para crear un archivo aparte del mapa

17.8 De la métrica al argumento biológico

Calcular esperanzas de vida y tiempos generacionales es la mitad fácil. La mitad difícil —y la que separa un análisis presentable de uno que sobrevive la revisión por pares— es construir un argumento biológico a partir de las métricas, no sólo reportarlas.

A continuación se ilustra el patrón en cuatro pasos, usando los objetos calculados arriba (esperanza_vida, tiempo_gen, edad_madurez) sobre el subconjunto filtrado Mat_erg_irred.

17.8.1 Paso 1 — Tabla resumen por hábito de vida

Combinamos las tres métricas con el OrganismType correspondiente para comparar epífitas vs. terrestres:

Código
# Construir un data frame con las tres métricas + hábito de vida
metricas <- tibble(
  habito = cdb_metadata(Mat_erg_irred)$OrganismType,
  esperanza_vida = esperanza_vida,
  tiempo_gen = tiempo_gen,
  edad_madurez = edad_madurez
) %>%
  drop_na() %>%
  mutate(
    habito = case_when(
      habito == "Epiphyte" ~ "Epífita",
      habito == "Herbaceous perennial" ~ "Terrestre",
      TRUE ~ habito
    )
  )

# Resumen por hábito
metricas %>%
  group_by(habito) %>%
  summarise(
    n               = n(),
    esperanza_med   = round(median(esperanza_vida, na.rm = TRUE), 2),
    tiempo_gen_med  = round(median(tiempo_gen, na.rm = TRUE), 2),
    edad_madurez_med = round(median(edad_madurez, na.rm = TRUE), 2)
  ) %>%
  flextable()

habito

n

esperanza_med

tiempo_gen_med

edad_madurez_med

Epífita

195

10.28

38.55

7.99

Terrestre

185

3.83

26.61

6.84

17.8.2 Paso 2 — Pregunta concreta

¿Las epífitas tienen tiempos generacionales más largos que las terrestres? Si así fuera, sería evidencia de que viven en un régimen “lento” (longevidad alta, reproducción tardía) coherente con su hábito —un sustrato menos predecible favorece el riesgo distribuido a través de muchos eventos reproductivos pequeños.

17.8.3 Paso 3 — Visualización antes que estadística

Código
ggplot(metricas, aes(x = habito, y = tiempo_gen, fill = habito)) +
  geom_boxplot(alpha = 0.7) +
  geom_jitter(width = 0.15, alpha = 0.5) +
  ylab("Tiempo generacional (años)") +
  xlab("Hábito de vida") +
  theme(legend.position = "none") +
  rlt_style_fill()

17.8.4 Paso 4 — La discusión que un revisor pediría

Suponga que el gráfico muestra una mediana mayor en epífitas. Antes de afirmar que esto refleja una diferencia evolutiva real, un revisor crítico preguntará:

AdvertenciaLas cuatro preguntas que un revisor hará
  1. ¿Pseudoreplicación? Una sola especie (p. ej. Lepanthes caritensis) puede contribuir varias matrices del mismo estudio. Si esa especie está en uno solo de los grupos, el resultado puede deberse a esa especie, no al hábito de vida. Verifíquelo con count(metricas, SpeciesAccepted) y use modelos mixtos con la especie como efecto aleatorio para inferencias formales.
  2. ¿Sesgo geográfico? ¿Las epífitas en su muestra son tropicales y las terrestres templadas? La diferencia que ve podría reflejar el clima, no el hábito. Mapéelas (sección anterior) y considere agregar latitud como covariable.
  3. ¿Sesgo de detección? Las orquídeas terrestres con latencia subterránea son menos detectables; sus tiempos generacionales pueden estar subestimados si la latencia no se modeló (ver capítulos sobre etapas crípticas y fecundidad). Reporte qué especies tienen MatrixCriteriaOntogeny con etapas latentes.
  4. ¿Calidad de la matriz? ¿Filtró por check_NA_A, check_ergodic y check_irreducible? ¿Las matrices que pasaron tienen colSums(matU) ≤ 1? Sin esas garantías, los números son numéricamente válidos pero biológicamente sospechosos (ver el capítulo sobre datos sin sentido biológico).

Un análisis comparativo que anticipe estas cuatro preguntas en su discusión —y muestre los gráficos / estadísticas correspondientes— es el que sobrevive la revisión por pares. Reportar la métrica sin enfrentarlas es invitar al rechazo.


17.9 Ejercicios — Pruebe usted mismo

TipEjercicio 1 — Esperanza de vida por especie

Calcule la mediana de la esperanza de vida (life_expect_mean) para cada especie de orquídea en COMPADRE con al menos dos matrices. ¿Cuál es la especie con la esperanza de vida más alta? ¿Y la más baja? ¿Tiene sentido biológico?

TipEjercicio 2 — Tiempo generacional ~ longevidad

Cree un gráfico de dispersión de gen_time contra life_expect_mean para todas las matrices del subconjunto. ¿Hay correlación? ¿Qué especies se separan del patrón general?

TipEjercicio 3 — Sensibilidad al start

Recalcule life_expect_mean con start = 2L (juvenil) y start = N (donde N es la última etapa). Compare con los resultados originales (start = 1L). ¿Cuánto cambia? ¿Qué reportaría usted en un manuscrito —y por qué?

TipEjercicio 4 — Iteroparidad vs. semelparidad

Use Rage::entropy_d() sobre el subconjunto. ¿Las orquídeas son más iteróparas (entropía baja) o más semélparas (entropía alta)? Compare con grupos no-orquídeas usando otro Family en COMPADRE.

Tremblay R, Ackerman J. 2001. Gene flow and effective population size in Lepanthes (Orchidaceae): a case for genetic drift. Biological Journal of the Linnean Society 72:47-62. DOI: 10.1006/bijl.2000.0485.
Tremblay R, McCarthy MA. 2014. Bayesian estimates of transition probabilities in seven small lithophytic orchid populations: maximizing data availability from many small samples. PLoS One 9:e102859.