testNM: Null Model Approach for Animal Movement Analysis

View source: R/testNM.r

testNMR Documentation

Null Model Approach for Animal Movement Analysis

Description

The functions NMs.* allow to define "single null models" (see details). The function NMs2NMm can be used on an object of class "NMs" to define "multiple null models". The function testNM can be used to simulate the defined null models.

Usage

NMs.randomCRW(ltraj, rangles = TRUE, rdist = TRUE, fixedStart = TRUE,
              x0 = NULL, rx = NULL, ry = NULL, treatment.func = NULL,
              treatment.par = NULL, constraint.func = NULL,
              constraint.par = NULL, nrep = 999)

NMs.randomShiftRotation(ltraj, rshift = TRUE, rrot = TRUE,
                        rx = NULL, ry = NULL, treatment.func = NULL,
                        treatment.par = NULL, constraint.func = NULL,
                        constraint.par = NULL, nrep = 999)


NMs.CRW(N = 1, nlocs = 100, rho = 0, h = 1, x0 = c(0,0),
        treatment.func = NULL,
        treatment.par = NULL, constraint.func = NULL,
        constraint.par = NULL, nrep = 999)


NMs.randomCs(ltraj, Cs = NULL, rDistCs = TRUE,
             rAngleCs = TRUE,
             rCentroidAngle = TRUE, rCs = TRUE,
             newCs = NULL, newDistances = NULL,
             treatment.func = NULL, treatment.par = NULL,
             constraint.func = NULL, constraint.par = NULL,
             nrep=999)

NMs2NMm(NMs, treatment.func = NULL,
        treatment.par = NULL, constraint.func = NULL,
        constraint.par = NULL, nrep = 999)

## S3 method for class 'NMm'
print(x, ...)

## S3 method for class 'NMs'
print(x, ...)

testNM(NM, count = TRUE)

Arguments

ltraj

an object of class "ltraj"

rangles

logical. Whether the turning angles should be randomized.

rdist

logical. Whether the distances between successive relocations should be randomized.

fixedStart

logical. If TRUE, the first location of the randomized trajectories corresponds to x0. If FALSE, the first location (x, y) is sampled in the interval (rx, ry)

x0

a vector of length 2 giving the x and y coordinates of the first relocations. If NULL and fixedStart=TRUE, the first location of the trajectory corresponds to the first location of the actual trajectory

rx

a vector of length 2 giving the x coordinates of the bounding box where the first location of the trajectory should be sampled

ry

a vector of length 2 giving the range (min, max) of the y coordinates of the bounding box where the first location of the trajectory should be sampled

treatment.func

any function taking two arguments x and par, where x is the trajectory generated by the function, and par can be any R object (e.g. a list containing the parameters needed by the function. Note that the argument par should be present in the function definition even if it is not needed in the function). See details and examples. If NULL, a function is defined internally that simply returns the raw trajectory simulated by the model

treatment.par

the R object that will be passed as an argument to the parameter par of the function treatment.func

constraint.func

any function taking two arguments x and par, where x is the trajectory generated by the function, and par can be any R object (e.g. a list containing the parameters needed by the function). **This function should necessarily return a logical value** (See details and examples). If NULL, a function is defined internally that always returns TRUE

constraint.par

The R object that will be passed as an argument to the parameter par of the function constraint.func

nrep

The number of repetitions of the null model

rshift

logical. Whether the trajectory should be shifted over the study area.

rrot

logical. Whether the trajectory should be rotated around its barycentre.

N

The number of animals to simulate.

nlocs

The number of relocations building up each trajectory

rho

The concentration parameter for wrapped normal distribution of turning angles (see ?simm.crw)

h

the scaling parameter for the movement length (see ?simm.crw)

Cs

a list of vectors of length 2. Each vector should contain the x and y coordinates of the capture sites of the animals in ltraj. This list should therefore have the same number of elements as ltraj

rDistCs

logical. Whether the distances between the barycentre of the trajectories and the corresponding capture sites should be randomized among trajectories

rAngleCs

logical. Whether the angle between the east direction and the line connecting the capture site and the barycentre of the trajectory should be drawn from an uniform distribution.

rCentroidAngle

logical. Whether the trajectory should be randomly rotated around its barycentre.

rCs

logical. Whether the trajectory should be randomly associated to a new capture site.

newCs

a list of vectors of length 2. Each vector should contain the x and y coordinates of new capture sites. If NULL and rcs=TRUE, the new capture sites are sampled in cs

newDistances

a vector of new distances that will be used to define the distances between capture sites and centroid of simulated trajectories if rDistCs=TRUE

NM,x

a null model of class "NMs" or "NMm"

NMs

a null model of class "NMs"

count

whether the iterations should be displayed

...

additionnal arguments to be passed to or from other methods

Details

The null model approach has been considered as a useful approach in many fields of ecology to study biological processes. According to Gotelli and Graves (1996), "A null model is a pattern-generating model that is based on randomization of ecological data or random sampling from a known or imagined distribution. The null model is designed with respect to some ecological or evolutionary process of interest. Certain elements of the data are held constant, and others are allowed to vary stochastically to create new assemblage patterns. The randomization is designed to produce a pattern that would be expected in the absence of a particular ecological mechanism".

This approach can be very useful to test hypotheses related to animal movements. The package adehabitatLT propose several general null models that can be used to test biological hypotheses. For example, imagine that we want to test the hypothesis that no habitat selection occurs when the animal moves. The shape of the trajectory, under this hypothesis would be the pure result of changing activity (moving, foraging, resting). Therefore, a possible approach to test whether habitat selection actually occurs would be to randomly rotate the trajectory around its barycentre and shifting it over the study area. The function NMs.randomShiftRotation can be used to define such a model. It is possible to constrain the randomization by defining a "constraint function" (e.g. to keep only the randomized trajectories satisfying a given criterion). It is required to specify a "treatment function" (i.e., a function that will be applied to each randomized trajectory). Once the null model has been defined, it is then possible to perform the randomizations using the function testNM. We give below the details concerning the available null models, as well as the constraint and the treatment functions.

First, two types of null models can be defined: single (NMs) and multiple (NMm) null models. Consider an object of class "ltraj" containing N bursts. With NMs, the treatment function will be applied to each randomized burst of relocations. Thus, for example, if nrep repetitions of the null model are required, nrep repetitions of the null models will be carried out for each burst separately. The treatment function will be applied on each randomized burst. With NMm, for each repetition, N randomized bursts of relocations are generated. The treatment is then applied, for each repetition, to the whole set of N randomized bursts. Thus, NMs are useful to test hypothesis on each trajectory separately (e.g. individual habitat selection), whereas NMm are useful to test hypotheses relative to the whole set of animals stored in an object of class ltraj (e.g. interactions between animals). The only current way to define an object of class NMm is to first define an object of class NMs and then use the function NMs2NMm to indicate the treatment function that should be applied on the whole set of trajectories.

The constraint function should be user-defined. It should return a logical value indicating whether the constraint is satisfied. With NMs, this function should take only two parameters: x and par. The argument x is a data frame with three columns describing a trajectory (the X and Y coordinates, and the date as a vector of class "POSIXct"), and the argument par can be any R object required by the constraint function (e.g. if the constraint to keep 80% of the relocations of the randomized trajectories within a given habitat type, the parameter par can be a raster map, or a list of raster maps). With NMm, this function should also take only the two parameters x and par. The argument par can be any R object required by the constraint function. However, when "NMm" are defined, the argument x of the constraint function should be an object of class "ltraj". If the function NMs2NMm is used to define the object of class "NMm", two types of constraint can therefore be defined: at the individual level (in the function NMs.*) and for the whole set of animals (in the function NMs2NMm). In this case, some constraints will be satisfied at the individual level, and others at the scale of the whole set of animals. If no constraint function is defined by the user, a constraint function always returning TRUE is automatically defined internally.

The treatment function can be any function defined by the user, but should take two arguments x and par, identical to those passed to the constraint function (i.e., x should be a data frame with three columns for NMs and an object of class "ltraj" for NMm. Note that only one treatment function can be applied to the randomization: if NMs2NMm is used to define an object of class NMm, the treatment function defined in the function NMs.* will be ignored, and only the treatment function defined in the function NMs2NMm will be taken into account. If no treatment function is defined by the user, a treatment function will be defined internally, simply returning the randomized trajectory (i.e. a data.frame with three columns for NMs, and an object of class ltraj for NMm).

We now describe the list of available null models:

NMs.CRW: this model is a purely parametric model. It simulates a correlated random walk with specified parameters (see ?simm.crw for a complete description of this model).

NMs.randomCRW: this model also simulates a correlated random walk, but the distributions of the turning angles and/or distances between successive relocations are derived from the trajectories passed as arguments. It is possible to randomize the turning angles, the distances between successive relocations, or both (default).

NMs.randomShiftRotation: this model randomly rotates the trajectory around its barycentre and randomly shifts it over the study area (but does not change its shape). The function allows for a random rotation, a random shift or both operations (default).

NMs.randomCs: this model is similar to the previous one: it keeps the shape of the trajectory unchanged. However, it randomizes the position of the trajectories with respect to a set of capture sites (it can be used to take into account the fact that a the home range of a sedentary animal captured at a given place is likely to be close to this place). First a capture site may be randomly drawn from a list of capture sites (either the actual capture sites or a list passed by the user). Then, the angle between the east direction and the line connecting the capture site of the animal and the barycentre of its trajectory is randomly drawn from a uniform distribution. Then, the distance between this barycentre and the capture site is randomly drawn from the observed distribution of distances between capture sites and trajectory barycentre (or from a set of distances passed as argument). Finally, the trajectory is randomly rotated around its barycentre.

Value

For objects of class "NMs" a list of N elements (where N is the number of trajectories in the object of class "ltraj" passed as argument, with each element is a list storing the nrep results of the treatment function applied to each randomized trajectory.

For objects of class "NMm", a list of nrep elements, each element storing the result of the treatment function applied to each set of N randomized trajectories.

Author(s)

Clement Calenge clement.calenge@ofb.gouv.fr

References

Gotelli, N. and Graves, G. (1996) Null models in Ecology. Smithsonian Institution Press.

Richard, E., Calenge, C., Said, S., Hamann, J.L. and Gaillard, J.M. (2012) Studying spatial interactions between sympatric populations of large herbivores: a null model approach. Ecography, in press.

See Also

as.ltraj for additional information about objects of class "ltraj"

Examples

## Not run: 
########################################
##
## example using NMs.randomShiftRotation

## first load the data:
data(puechcirc)
data(puechabonsp)
map <- puechabonsp$map

## Consider the first animal
## on an elevation map
anim1 <- puechcirc[1]
plot(anim1, spixdf=map[,1])

## We define a very simple treatment function
## for a NMs model: it just plots the randomized trajectory
## over the study area
## As required, the function takes two arguments:
## x is a data.frame storing a randomized trajectory (three
## columns: the x, y coordinates and the date)
## par contains the map of the study area

myfunc <- function(x, par)
{
   par(mar = c(0,0,0,0))
   ## first plot the map
   image(par)

   ## then add the trajectory
   lines(x[,1], x[,2], lwd=2)
}

## Then we define the null model
##
## We define the range of the study area where the trajectory
## will be shifted:
rxy <- apply(coordinates(map),2,range)
rxy

## We define the null model with 9 repetitions
nmo <- NMs.randomShiftRotation(na.omit(anim1), rshift = TRUE, rrot = TRUE,
                               rx = rxy[,1], ry = rxy[,2], treatment.func = myfunc,
                               treatment.par = map, nrep=9)

## Then apply the null model
par(mfrow = c(3,3))
tmp <- testNM(nmo)

## You may try variations, by setting rshift or rrot to FALSE, to see
## the differences

## Note that some of the randomized trajectories are located outside the
## study area, although all barycentres are located within the X and Y
## limits of this study area.
## We may define a constraint function returning TRUE only if all
## relocations are located within the study area

## again, note that the two parameters are x and par
consfun <- function(x, par)
{
   ## first convert x to the class SpatialPointsDataFrame
   coordinates(x) <- x[,1:2]

   ## then use the function over from the package sp
   ## to check whether all points in x are located inside
   ## the study area
   ov <- over(x, geometry(map))
   return(all(!is.na(ov)))  
}

## Now fit again the null model under these constraints:
nmo2 <- NMs.randomShiftRotation(na.omit(anim1), rshift = TRUE, rrot = TRUE,
                                rx = rxy[,1], ry = rxy[,2], treatment.func = myfunc,
                                treatment.par = map,
                                constraint.func = consfun,
                                constraint.par = map, nrep=9)

## Then apply the null model
par(mfrow = c(3,3))
tmp <- testNM(nmo2)

## all the relocations are now inside the study area.


########################################
##
## example using NMs.randomCRW


## We generate correlated random walks with the same starting
## point as the original trajectory, the same turning angle
## distribution, and the same distance between relocation
## distribution. We use the same constraint function as previously
## (all relocations falling within the study area), and we
## use the same treatment function as previously (just plot
## the result).
mo <- NMs.randomCRW(na.omit(anim1), rangles=TRUE, rdist=TRUE,
                    treatment.func = myfunc,
                    treatment.par = map, constraint.func=consfun,
                    constraint.par = map, nrep=9)

par(mfrow = c(3,3))
tmp <- testNM(mo)

## Now, try a different treatment function: e.g. measure
## the distance between the first and last relocation,
## to test whether the animal is performing a return trip
myfunc2 <- function(x, par)
{
    sqrt(sum(unlist(x[1,1:2] - x[nrow(x),1:2])^2))
}

## Now fit again the null model with this new treatment and 499 repetitions:
mo2 <- NMs.randomCRW(na.omit(anim1), rangles=TRUE, rdist=TRUE,
                     treatment.func = myfunc2,
                     treatment.par = map, constraint.func=consfun,
                     constraint.par = map, nrep=499)

## Then apply the null model
suppressWarnings(RNGversion("3.5.0"))
set.seed(298) ## to make the calculation reproducible
rand <- testNM(mo2)

## rand is a list with one element (there is one trajectory in anim1).
length(rand[[1]])

## The first element of rand is a list of length 499 (there are 499
## randomizations).
head(rand[[1]])

## unlist this list:
rand2 <- unlist(rand[[1]])

## calculate the observed average elevation:
obs <- myfunc2(na.omit(anim1)[[1]][,1:3], map)

## and performs a randomization test:
(rt <- as.randtest(rand2, obs, alter="less"))
plot(rt)

## Comparing to a model where the animal is moving randomly, and based
## on the chosen criterion (distance between the first and last
## relocation), we can see that the distance between the first and last
## relocation is rarely observed.  It seems to indicate that the animal
## tends to perform a loop.



########################################
##
## example using NMs2NMm

## Given the previous results, we may try to see if all
## the trajectories in puechcirc are characterized by return
## trips
## We need a NMm approach. Because we have 3 burst in puechcirc
## we need a summary criterion. For example, the mean
## distance between the first and last relocation.

## We program a treatment function: it also takes two arguments, but x
## is now an object of class "ltraj" ! 
## par is needed, but will not be used in the function

myfunm <- function(x, par)
{
   di <- unlist(lapply(x, function(y) {
      sqrt(sum(unlist(y[1,1:2] - y[nrow(y),1:2])^2))
   }))
   return(mean(di))
}

## Now, prepare the NMs object: we do not indicate any treatment
## function (it would not be taken into account when NMs would be
## transformed to NMm).  However, we keep the constraint function
## the simulated trajectories should fall within the study area
mo2s <- NMs.randomCRW(na.omit(puechcirc), constraint.func=consfun,
                      constraint.par = map)

## We convert this object to NMm, and we pass the treatment function
mo2m <- NMs2NMm(mo2s, treatment.func = myfunm, nrep=499)

## and we fit the model
suppressWarnings(RNGversion("3.5.0"))
set.seed(908)
resu <- testNM(mo2m)

## We calculate the observed mean distance between the
## first and last relocation
obs <- myfunm(na.omit(puechcirc))

## and performs a randomization test:
(rt <- as.randtest(unlist(resu), obs, alter="less"))
plot(rt)

## The test is no longer significant


########################################
##
## example using NMs.randomCs

## Consider this sample of 5 capture sites:
cs <- list(c(701184, 3161020), c(700164, 3160473),
           c(698797, 3159908), c(699034, 3158559),
           c(701020, 3159489))
image(map)
lapply(cs, function(x) points(x[1], x[2], pch=16))

## Consider this sample of distances:
dist <- c(100, 200, 150)

## change the treatment function so that the capture sites are showed as
## well. Now, par is a list with two elements: the first one is the map
## and the second one is the list of capture sites

myfunc <- function(x, par)
{
   par(mar = c(0,0,0,0))
   ## first plot the map
   image(par[[1]])

   lapply(par[[2]], function(x) points(x[1], x[2], pch=16))

   ## then add the trajectory
   lines(x[,1], x[,2], lwd=2)
}


## Now define the null model, with the same constraints
## and treatment as before
mod <- NMs.randomCs(na.omit(anim1), newCs=cs, newDistances=dist,
                    treatment.func=myfunc, treatment.par=list(map, cs),
                    constraint.func=consfun, constraint.par=map,
                    nrep=9)

## apply the null model
par(mfrow = c(3,3))
tmp <- testNM(mod)

## End(Not run)



adehabitatLT documentation built on April 6, 2023, 5:18 p.m.