Análisis de datos de ocupación

Práctica 2, Métodos en Biología de la Conservación

Máster en Áreas Protegidas, Recursos Naturales y Biodiversidad

Profesores
Departamento

Ecología e Hidrología, Facultad de Biología

Fecha de publicación

22 de octubre de 2023

Fecha de actualización

22 de octubre de 2025

Introducción

En esta práctica trabajaremos con el paquete unmarked de R para el análisis de modelos de ocupación. Utilizaremos diversos datos de ejemplo para realizar análisis single-season, de comunidades, multi-season y multi-state. Aprenderemos a diseñar e interpretar cuantitativamente los resultados de los modelos, a interpretar tablas para la selección de modelos, y a realizar estimaciones de probabilidad de ocupación mediante el procedimiento de model averaging.

Preparación

Una vez iniciado R debemos cargar el archivo de datos y funciones de la asignatura (mbc.RData) accediendo al servidor con la siguiente función:

load( url( "https://webs.um.es/jfcalvo/mbc.RData" ) )

Usando ls() podemos ver los objetos cargados. Utiliza la función info para obtener información sobre ellos; por ejemplo: info( "weta" ) o info( "nso" ). Teclea info() para más información.

Necesitaremos además los paquetes unmarked y AICcmodavg. Si no los tenemos instalados ejecutaremos:

install.packages( c( "unmarked", "AICcmodavg" ) )

Una vez instalados los cargaremos en memoria:

library( unmarked )
library( AICcmodavg )

Modelos single-season. Ejemplo del weta

Trabajaremos inicialmente con los datos del weta gigante (Mahoenui giant weta, Deinacrida mahoenui) un ortóptero de la familia Anostostomatidae endémico de Nueva Zelanda. La presencia de esta especie fue muestreada en 72 parcelas circulares de 3 m de radio, visitadas en 5 días distintos de marzo de 2004. Como covariable de sitio se considera la existencia de ramoneo por cabras del arbusto Ulex europaeus. El ramoneo favorece el follaje de la planta, que aporta alimento y protección ante depredadores. Como covariable de muestreo se considera el efecto de 3 observadores distintos.

weta

Para trabajar con las funciones de unmarked necesitamos convertir la tabla de datos en un objeto de la clase unmarkedFrameOccu, especificando los datos de ocupación, las covariables de los sitios o unidades de muestreo y las covariables correspondientes a cada día de observación:

datos <- weta [ , 1 : 5 ]
browsed <-  data.frame( browsed = weta[ , 6 ] )
observer <- data.frame( weta[ , 7 : 11 ] )
observer <- data.frame( lapply( observer, factor  ) )
wetaUF <- unmarkedFrameOccu( y = datos, siteCovs = browsed, obsCovs = list( observer = observer ) )
wetaUF
summary( wetaUF )

Diseñaremos y ejecutaremos diversos modelos con la función occu, con diferentes especificaciones para estimar la probabilidad de detección y la probabilidad de ocupación (en este orden). Los efectos del ramoneo se especifican con la variable browsed, los efectos del día de visita con obsNum y los del observador con observer. Con el argumento -1 el modelo no estima el intercept, por lo que obtenemos un coeficiente propio para cada día de observación. Una vez realizados los análisis procedamos a: (1) interpretar los resultados de cada modelo, (2) analizar la tabla de selección de modelos y sus parámetros, y (3) realizar el model averaging de las estimaciones.

Modelo nulo: \(p\) constante, \(\psi\) constante

occu( ~ 1 ~ 1, data = wetaUF ) -> m0
m0

Modelo 1: \(p\) dependiente de la visita, \(\psi\) constante

occu( ~ -1 + obsNum ~ 1, data = wetaUF ) -> m1
m1

Modelo 2: \(p\) dependiente de la visita, \(\psi\) dependiente del ramoneo

occu( ~ -1 + obsNum ~ browsed, data = wetaUF ) -> m2
m2

Modelo 3: \(p\) dependiente de la visita y del observador, \(\psi\) dependiente del ramoneo

occu( ~ -1 + obsNum + observer ~ browsed, data = wetaUF ) -> m3
m3

Los valores estimados de \(\psi\) (argumento state) y \(p\) (argumento det) se obtienen con la función predict. Por ejemplo:

predict( m0, "state" )
predict( m0, "det" )

Observa que en el caso de \(\psi\) obtenemos 72 valores (para cada uno de los sitios o unidades de muestreo), mientras que en el caso de \(p\) obtenemos 360 (uno para cada sitio y visita: \(72 \times 5\)). Podemos comprobar que ambas probabilidades se calculan a partir de los coeficientes aplicando la transformación logística inversa mediante la función plogis.

summary( m0 )
plogis( 0.475124 )
plogis( -0.621831 )

En el caso del modelo 2, las probabilidades de ocupación de sitios ramoneados y no ramoneados son, respectivamente:

summary( m2 )
plogis( -0.027318 + 1.235149 )
plogis( -0.027318 )
head( predict( m2, "state" ) )

Observa también que los valores estimados de detectabilidad varían para cada visita:

head( predict( m2, "det" ) )

Podemos representar los resultados usando la función plotp.ic (disponible en el archivo mbc.RData) con los valores estimados por predict. Por ejemplo, las probabilidades de ocupación:

predict( m2, "state" ) -> m2ps
plotp.ic( m2ps[, c( 1, 3 : 4 ) ], ylim = c( 0, 1 ), ylab = "Probabilidad de ocupación", grupos = c( "Ramoneado", "No ramoneado" ) )

Y las probabilidades de detección:

predict( m2, "det" ) -> m2pd
plotp.ic( m2pd[, c( 1, 3 : 4 ) ], ylim = c( 0, 1 ), ylab = "Probabilidad de detección", grupos = c( "Visita 1", "Visita 2", "Visita 3", "Visita 4", "Visita 5" ) )

El procedimiento de selección de modelos se realiza con:

fitList( m0, m1, m2, m3 ) -> ms
modSel( ms )

Los resultados completos (y con mayor número de decimales) se obtienen con:

modSel( ms )@Full

Finalmente, el procedimiento de model averaging se realiza con:

predict( ms, "state" )
predict( ms, "det" )

Observa que el caso de las probabilidades de detección tenemos múltiples valores que corresponden a diferentes observadores y visitas. Podemos visualizarlos con mayor claridad si escribimos lo siguiente:

t( matrix( ( predict( ms , "det" )[ , 1]), 5, 72) )

Comprueba que la probabilidad de ocupación estimada en sitios ramoneados, de acuerdo con el model averaging es:

0.7674 * 0.6180 + 0.7699 * 0.2466 + 0.6298 * 0.1251 + 0.6166 * 0.0103
NotaEjercicio 1
  • Comprueba que, de acuerdo con el modelo 3 la probabilidad de detección estimada correspondiente al cuarto día de muestro y al observador 2 es:
plogis( -1.370 + 0.727 )
  • Observa el efecto que tiene eliminar el argumento -1 en la especificación de los modelos. Por ejemplo:
occu( ~ obsNum ~ 1, data = wetaUF ) -> m1b
summary( m1b )
  • Comprueba que la probabilidad de ocupación estimada por model averaging en sitios no ramoneados es:
0.5060 * 0.6180 + 0.4932 * 0.2466  + 0.6298 * 0.1251 + 0.6166 * 0.0103

Pruebas de bondad de ajuste

La función mb.gof.test del paquete AICcmodavg permite realizar pruebas de bondad de ajuste de los modelos de ocupación single-season y multi-season (siguiente sección), con la estimación del factor de inflación de la varianza \(\hat{c}\). Por ejemplo:

mb.gof.test( m3, nsim = 100 )

También dispone de una función que proporciona una tabla de selección de modelos basada en el AIC corregido (AICc) y en el quasi AIC (QAICc):

aictab( c( m0, m1, m2, m3 ) )
aictab( c( m0, m1, m2, m3 ), c.hat = 1.3 )

Observa las diferencias entre estas tablas y la proporcionada por la función modSel de unmarked.

Modelos de ocupación de comunidades

Cuando se trabaja con múltiples especies en estudios de comunidades, adquiere especial interés la estimación de los valores de riqueza (número de especies), que debido a la detección imperfecta son siempre superiores a los valores observados. La función occuComm del paquete unmarked permite realizar este tipo de análisis. Como ejemplo utilizaremos los datos de presencia/ausencia de 60 especies de aves en itinerarios de censo de 1 km de longitud (3 visitas), realizados en 34 localizades (zonas agroforestales) de la Región de Murcia. Los datos, procedentes de una tesis doctoral realizada en la Universidad de Murcia (Zamora 2021), están disponibles en el objeto avesUF, de la clase unmarkedFrameOccuComm.

© José F. Calvo

© José F. Calvo
avesUF

Por defecto solo se muestran los datos de la primera especie, junto con la covariable ambiental altitud y la covariable de observación (visita). También se incluye la riqueza observada de cada itinerario (riq.obs) con objeto de realizar la comparación con las estimaciones de los modelos.

Si queremos visualizar los datos de todas las especies debemos utilizar:

avesUF@ylist

La función occuComm realiza análisis de ocupación para el conjunto de las especies. Por ejemplo:

occuComm( ~ visita ~ altitud, data = avesUF ) -> mc1
mc1

Para cada especie, las probabilidades de ocupación estimadas por el modelo, se obtienen con predict:

lapply( predict( mc1, "state"), head )

También las probabilidades de detección:

lapply( predict( mc1, "det"), head )

Si queremos obtener las estimaciones de una especie concreta podemos usar el nombre o su índice La estimación de la riqueza para cada localidad se obtiene con:

richness( mc1 )

De esta forma, podemos comparar riquezas observadas y estimadas mediante el siguiente gráfico:

plot( avesUF@siteCovs$riq.obs, richness( mc1 ) )
abline( 0, 1 )

Modelos multi-season. Ejemplo del búho moteado

Utilizaremos en este caso los datos de ejemplo del búho moteado (Strix occidentalis caurina) correspondendientes a un estudio realizado en California entre 1997 y 2001, en el que 55 territorios fueron visitados hasta en 8 ocasiones durante la época de reproducción para determinar la presencia de los búhos, es decir, la ocupación de cada territorio (objeto nso).

nso
dim( nso )

Los dos nuevos parámetros que aparecen en este tipo de modelos son \(\gamma\) (probabilidad de colonización) y \(\varepsilon\) (probabilidad de extinción local). Aun sin covariables, el mayor número de parámetros a estimar determina que el número total de modelos que podrían considerarse como candidatos sea elevado. Por tanto, en general, la investigación debe centrarse en un conjunto más reducido de modelos atendiendo a hipótesis concretas. Por ejemplo, podemos limitar el número de hipótesis sobre las probabilidades de detección asumiendo que estas son constantes (no varían entre visitas ni entre años). En consecuencia, todos los modelos que vamos a ejecutar inicialmente cuentan con una estructura fija para las probabilidades de detección (\(p\) constante).

Al igual que en la sección anterior, debemos transformar la tabla de datos original (nso) para convertirla en este caso en un objeto de la clase unmarkedMultFrame:

year <- data.frame( matrix( rep( 1997 : 2001, each = 55 ), 55, 5 ) )
year <- data.frame( lapply( year, factor ) )
survey <- data.frame( matrix( rep( 1 : 8, each = 55 ), 55, 8 * 5 ) )
survey <- data.frame( lapply( survey, factor ) )
nsoUF <- unmarkedMultFrame( y = nso, obsCovs = list( visita = survey ), yearlySiteCovs = list( año = year ), numPrimary = 5 )
nsoUF
summary( nsoUF )

Procederemos a diseñar y ejecutar los siguientes modelos:

Modelo 0 (nulo): \(\psi\) variable anualmente, \(\gamma\) constante, \(\varepsilon\) constante, \(p\) constante

colext( psiformula = ~ 1, gammaformula = ~ 1, epsilonformula = ~ 1, pformula = ~ 1, data = nsoUF) -> mm0
summary( mm0 )
predict( mm0, type = "psi" )[ 1, ]
predict( mm0, type = "col" )[ 1, ]
predict( mm0, type = "ext" )[ 1, ]
predict( mm0, type = "det" )[ 1, ]
projected( mm0 )

Este modelo estima la probabilidad de ocupación del primer año (1997). Los parámetros derivados (calculados apartir de los parámetros estimados) son las probabilidades de ocupación a partir del segundo año (\(\psi_{1998 - 2001}\)) y las tasas de cambio anual (\(\lambda_{t}\)):

\[\psi_{t + 1} = \psi_{t} + {\ \gamma}_{t}\left( 1 - \psi_{t} \right) - \varepsilon_{t}{\ \psi}_{t}\]

\[\lambda_{t} = \frac{\psi_{t + 1}}{\psi_{t}}\] Comprueba que \({\ \psi}_{1997}\), \(\gamma\), \(\varepsilon\) y \(p\) se calculan a partir de los coeficientes del modelo:

plogis( 0.537 )
plogis( -1.49 )
plogis( -1.73 )
plogis( -0.021 )

Comprueba también que, por ejemplo, \({\ \psi}_{1998}\) y \(\lambda_{1997}\) se calculan como:

0.63116 + 0.18418 * ( 1 - 0.63116 ) - 0.15074 * 0.63116
0.6039519 / 0.63116

Modelo 1: \(\psi\) variable anualmente, \(\gamma\) variable anualmente, \(\varepsilon\) constante, \(p\) constante

colext( psiformula= ~ 1, gammaformula = ~ -1 + año, epsilonformula = ~ 1, pformula = ~ 1, data = nsoUF ) -> mm1
summary( mm1 )
projected( mm1 )

Comprueba que, en este caso, las tasas de colonización son diferentes cada año:

predict( mm1, type = "col" )

Modelo 2: \(\psi\) variable anualmente, \(\gamma\) constante, \(\varepsilon\) variable anualmente, \(p\) constante

colext(psiformula= ~ 1, gammaformula = ~ 1, epsilonformula = ~ -1 + año, pformula = ~ 1, data = nsoUF ) -> mm2
summary( mm2 )
projected( mm2 )

Modelo 3: \(\psi\) variable anualmente, \(\gamma\) variable anualmente, \(\varepsilon\) variable anualmente, \(p\) constante

colext(psiformula= ~ 1, gammaformula = ~ -1 + año, epsilonformula = ~ -1 + año, pformula = ~ 1, data = nsoUF ) -> mm3
summary( mm3 )
projected( mm3 )

Para obtener la tabla de selección de modelos y el model averaging utilizaremos:

fitList( mm0, mm1, mm2, mm3 ) -> mms
modSel( mms )
predict( mms, type = "psi" )[ 1, ]
predict( mms, type = "col" )[ 1 : 5, ]
predict( mms, type = "ext" )[ 1 : 5, ]
predict( mms, type = "det" )[ 1 : 40, ]
NotaEjercicio 2

Para cada uno de los cuatro modelos anteriores, diseña y ejecuta otros dos modelos considerando distintas hipótesis sobre las probabilidades de detección: argumentos pformula = ~ -1 + visita, pformula = ~ -1 + año. Aplica al conjunto de modelos (12 en total) un procedimiento de selección.

Modelos multi-season multi-state

Analizaremos unos datos simulados sobre la ocupación y reproducción de una especie en 100 territorios, visitados en 3 ocasiones durante 5 años (objeto msms). Utilizaremos la función occuMS del paquete unmarked y ejecutaremos un único modelo estimando las probabilidades condicionales de ocupación y reproducción en función del estado previo de territorio. Los estados son: no ocupado (0), ocupado sin reproducción (1), ocupado con reproducción (2). Así, por ejemplo, \(\psi^{\lbrack 0\rbrack}\) (phi[0] en R) denota la probabilidad de ocupación de un territorio en el año t + 1 dado que no estaba ocupado en el año \(t\), y \(R^{\lbrack 2\rbrack}\) (R[2] en R) denota la probabilidad de reproducción de un territorio en el año \(t + 1\) dado que estaba ocupado con reproducción en el año \(t\).

De esta forma, es posible establecer una matriz de transición (proceso Markoviano), mediante la que se definen las diferentes probabilidades de cambio de estado de los territorios entre el año \(t\) (columnas) y el año \(t + 1\) (filas):

\[\text{A} = \begin{bmatrix} 1 - \psi^{\lbrack 0\rbrack} & 1 - \psi^{\lbrack 1\rbrack} & 1 - \psi^{\lbrack 2\rbrack} \\ \psi^{\lbrack 0\rbrack}\left( 1 - R^{\lbrack 0\rbrack} \right) & \psi^{\lbrack 1\rbrack}\left( 1 - R^{\lbrack 1\rbrack} \right) & \psi^{\lbrack 2\rbrack}\left( 1 - R^{\lbrack 2\rbrack} \right) \\ \psi^{\lbrack 0\rbrack}R^{\lbrack 0\rbrack} & \psi^{\lbrack 1\rbrack}R^{\lbrack 1\rbrack} & \psi^{\lbrack 2\rbrack}R^{\lbrack 2\rbrack} \end{bmatrix}\]

Por otra parte, existen tres parámetros de detección distintos: \(p_{t, j}^{\lbrack{1}\rbrack}\), la probabilidad de detectar la ocupación en la visita \(j\) del año \(t\) en un territorio ocupado sin reproducción en el año \(t\); \(p_{t, j}^{\lbrack{2}\rbrack}\), la probabilidad de detectar la ocupación en la visita \(j\) del año \(t\) en un territorio ocupado con reproducción en el año \(t\); y \(\delta_{t,j}\), la probabilidad de detectar la reproducción en la visita \(j\) del año \(t\) en un territorio ocupado con reproducción.

En primer lugar transformaremos la tabla de datos en un objeto de clase unmarkedFrameOccuMS, añadiendo las covariables de año y visita:

msms
year <- data.frame( matrix( rep( 1 : 5, each = 100 ), 100, 5 ) )
year <- data.frame( lapply( year, factor ) )
survey <- data.frame( matrix( rep( 1 : 3, each = 100 ), 100, 3 * 5 ) )
survey <- data.frame( lapply( survey, factor ) )
msmsUF <- unmarkedFrameOccuMS( y = msms, obsCovs = list( visita = survey ), yearlySiteCovs = list( año = year ), numPrimary = 5 )
summary( msmsUF )

Diseñaremos y ejecutaremos un único modelo en el que tanto la ocupación como la reproducción dependan del estado previo del territorio. Asumiremos también probabilidades de detección constantes, independientes de la visita y del año.

psiformulas <- c( "~ 1", "~ 1" ) # psi inicial, R inicial
phiformulas <- c( "~ 1", "~ 1", "~ 1", "~ 1", "~ 1", "~ 1" ) # psi[0], psi[1], psi[2], R[0], R[1], R[2]
detformulas <- c( "~ 1", "~ 1", "~ 1" ) # p[1], p[2], delta

occuMS( detformulas, psiformulas, phiformulas, data = msmsUF, parameterization = "condbinom" ) -> mmm0
summary( mmm0 )

Los valores estimados de las probabilidades condicionadas de ocupación y reproducción son:

lapply( predict( mmm0, type = "phi" ), head )

Los valores estimados de las probabilidades de detección son:

lapply( predict( mmm0, type = "det" ), head )

Podemos interpretar los resultados gráficamente representando las probabilidades de ocupación, reproducción y detección (con sus intervalos de confianza al 95 %) en función del estado previo. Usaremos la función plotp.ic. Por ejemplo:

rbind( c( 0.3158224, 0.2353254, 0.4091226 ), c( 0.1829915, 0.07321948, 0.3883711 ), c( 0.9510666, 0.8137157, 0.9885688) ) -> psi
psi
plotp.ic( psi, ylim = c( 0, 1 ), xlab = "Estado previo", ylab = "Probabilidad de ocupación", grupos = c( "0", "1", "2" ) )

Comprobaremos también que la matriz de transiciones se elabora a partir de los parámetros estimados según:

A <- matrix(NA, 3, 3)
A[ 1, ] <- 1 - c( 0.3158224, 0.1829915, 0.9510666 )
A[ 2, ] <- c( 0.3158224, 0.1829915, 0.9510666 ) * ( 1 - c( 0.1662257, 0.6848002, 0.8767159 ) )
A[ 3, ] <- c( 0.3158224, 0.1829915, 0.9510666 ) * c( 0.1662257, 0.6848002, 0.8767159 )
round ( A, 3 )
apply( A, 2, sum )
NotaEjercicio 3
  • Elabora un gráfico con las probabilidades de reproducción (y sus intervalos de confianza al 95 %) en función del estado previo del territorio.

  • Elabora un gráfico con las probabilidades de detección \(p^{\lbrack{1}\rbrack}\), \(p^{\lbrack{2}\rbrack}\) y \(\delta\) (y sus intervalos de confianza al 95 %).

Evaluación

Realiza la tarea de evaluación de la práctica publicada en el Aula Virtual.

Bibliografía

  • Conroy MJ, Carroll JP (2009) Quantitative conservation of vertebrates. Wiley-Blackwell, Oxford.

  • Fiske I, Chandler R (2011) unmarked: An R Package for Fitting Hierarchical Models of Wildlife Occurrence and Abundance. Journal of Statistical Software 43: 1-23.

  • Kéry M, Royle AJ (2016) Applied Hierarchical Modeling in Ecology. Volume 1. Elsevier, Amsterdam.

  • MacKenzie DI, Nichols JD, Royle JA, Pollock KH, Bailey LL, Hines JE (2018) Occupancy Estimation and Modeling - Inferring Patterns and Dynamics of Species Occurrence. 2nd ed. Academic Press.

  • Zamora JM (2021) Ecological contributions of small waterbodies to animal biodiversity in a Mediterranean semiarid region. Tesis doctoral, Universidad de Murcia.

Descripción de los datos

Utiliza la función info. Por ejemplo: info( "weta" ) o info( "nso" ).