unmarkedFollow the steps in this guide to add a new model to the
unmarked package. Note that the order can be adjusted based
on your preferences. For instance, you can start with the likelihood function, as it forms
the core of adding a model to unmarked, and then build the rest of the
code around it. In this document, the steps are ordered as they would
occur in an unmarked analysis workflow.
This guide uses the recently developed gdistremoval
function for examples, mainly because most of the relevant code is in a
single file instead of spread around. It also uses occu
functions to show simpler examples that may be easier to understand.
Before you start coding, you should use git to version your code:
unmarked repository on
Githubunmarked uses S4 for objects and methods - if you
aren’t familiar with S4 you may want to consult a book or tutorial such
as this
one.
If you are unfamiliar with building a package in R, here are two tutorials that may help you: Karl Broman’s guide to building packages and the official R-project guide. If you are using RStudio, their documentation on writing package could also be useful, especially to understand how to use the Build pane.
To avoid complex debugging in the end, I suggest you to regularly install and load the package as you add new code. You can easily do so in RStudio in the Build pane, by clicking on “Install > Clean and install”. This will also allow you to test your functions cleanly.
Write tests and documentation as you add new functions, classes, and methods. This eases the task, avoiding the need to write everything at the end.
unmarkedFrame objectMost model types in unmarked have their own
unmarkedFrame, a specialized kind of data frame. This is an
S4 object which contains, at a minimum, the response (y). It may also
include site covariates, observation covariates, primary period
covariates, and other info related to study design (such as distance
breaks).
In some cases you may be able to use an existing
unmarkedFrame subclass. You can list all the existing
unmarkedFrame subclasses by running the following code:
## Class "unmarkedFrame" [package "unmarked"]
##
## Slots:
##
## Name: y obsCovs siteCovs obsToY
## Class: matrix optionalDataFrame optionalDataFrame optionalMatrix
##
## Extends: "unmarkedFrameOrNULL"
##
## Known Subclasses:
## Class "unmarkedFrameOccuCOP", directly
## Class "unmarkedFrameDS", directly
## Class "unmarkedFrameMPois", directly
## Class "unmarkedFrameOccu", directly
## Class "unmarkedFrameOccuComm", directly
## Class "unmarkedFrameOccuFP", directly
## Class "unmarkedFrameOccuMulti", directly
## Class "unmarkedFramePCount", directly
## Class "unmarkedMultFrame", directly
## Class "unmarkedFrameOccuMS", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameOccuTTD", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameG3", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameGMM", by class "unmarkedFrameG3", distance 3
## Class "unmarkedFrameGDS", by class "unmarkedFrameG3", distance 3
## Class "unmarkedFrameGPC", by class "unmarkedFrameG3", distance 3
## Class "unmarkedFrameGOccu", by class "unmarkedFrameG3", distance 3
## Class "unmarkedFrameGDR", by class "unmarkedFrameG3", distance 3
## Class "unmarkedFrameDailMadsen", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameDSO", by class "unmarkedFrameDailMadsen", distance 3
## Class "unmarkedFrameMMO", by class "unmarkedFrameDailMadsen", distance 3
## Class "unmarkedFramePCO", by class "unmarkedFrameDailMadsen", distance 3
You can have more information about each unmarkedFrame
subclass by looking at the documentation of the function that was
written to create the unmarkedFrame object of this
subclass, for example with ?unmarkedFrameGDR, or on the package’s
website.
unmarkedFrame subclass for this modelunmarkedFrame subclasses are children of the
umarkedFrame class, defined here.occugdistremovalunmarkedFrame subclasses need to pass the validunmarkedFrame
validity check. You may want to add complementary validity check, like,
for example, the `unmarkedFrameDS
subclass.unmarkedFrame objectunmarkedFrame objectNote that you may not have to write all of the S4 methods below. Most
of them will work without having to re-write them, but you should test
it to verify it. All the methods associated with
unmarkedFrame objects are listed in the unmarkedFrame
class documentation accessible with
help("unmarkedFrame-class").
Here are methods you probably will have to rewrite.
unmarkedFrame object:
umf[i, ], umf[, j] and umf[i, j]
occu: code
for unmarkedFrame mother class, as used to subset an
unmarkedFrameOccu object.gdistremoval: umf[i, ]
when i is numeric, umf[i, ]
when i is logical, umf[i, j]Here are methods that you should test but probably will not have to
rewrite. They are defined in the unmarkedFrame.R
file, for the unmarkedFrame mother class.
getYnumSitesnumYobsCovsobsCovs<-obsNumobsToYobsToY<-plotprojectionshowsiteCovssiteCovs<-summaryYou may also need to add specific methods to allow users to access an
attribute you added to your unmarkedFrame subclass.
getL for
unmarkedFrameOccuCOPThe fitting function can be declined into three main steps: reading
the unmarkedFrame object, maximising the likelihood, and
formatting the outputs.
gdistremoval does it) instead of a
combined formula (e.g. the way occu does it).data for the unmarkedFrameoptim: optimisation algorithm
(method), initial parameters, and other parameters
(...)engine parameter to call one of the implemented
likelihood functionsunmarkedFrame object: write the getDesign
methodMost models have their own getDesign function, an S4
method. The purpose of this method is to convert the information in the
unmarkedFrame into a format usable by the likelihood
function.
unmarkedFrame.Writing the getDesign method is frequently the most
tedious and difficult part of the work adding a new function.
occu, as used for occugdistremovaloptim()
functionengine argument of
the fitting function.If you are mainly used to coding in R, you should probably start here. If users want to dig deeper into the likelihood of a model, it may be useful for them to be able to read the R code to calculate likelihood, as they may not be familiar with other languages. This likelihood function can be used only for fixed-effects models.
occugdistremoval doesn’t have an R version of the
likelihood functionThe C++ likelihood function is essentially a C++ version of the R
likelihood function, also designed exclusively for fixed-effects
models. This function uses the RcppArmadillo R
package, presented
here. In the C++ code, you can use functions of the
Armadillo C++ library, documented here.
Your C++ function should be in a .cpp file in the
./src/ folder of the package. You do not need to write a
header file (.hpp), nor do you need to compile the code by
yourself as it is all handled by the RcppArmadillo package.
To test if your C++ function runs and gives you the expected result, you
can compile and load the function with
Rcpp::sourceCpp(./src/nll_yourmodel.cpp), and then use it
like you would use a R function:
nll_yourmodel(params=params, arg1=arg1).
unmarkedEstimate objects per submodelOutputs from optim should be organized unto
unmarkedEstimate (S4) objects, with one
unmarkedEstimate per submodel (e.g. state,
detection). These objects include the parameter estimates and other
information about link functions etc.
The unmarkedEstimate class is defined here
in the unmarkedEstimate.R file, and the
unmarkedEstimate function is defined here,
and is used to create new unmarkedEstimate objects. You
normally will not need to create unmarkedEstimate
subclass.
unmarkedFit objectYou’ll need to create a new unmarkedFit subclass for
your model. The main component of unmarkedFit objects is a
list of the unmarkedEstimates described above.
unmarkedFit mother classunmarkedFitOccu subclass definitionunmarkedFitGDR subclass definitionAfter you defined your unmarkedFit subclass, you can
create the object in your fitting function.
The fitting function return this unmarkedFit object.
unmarkedFrameunmarkedFrame, other options to your
draft fitting functiongetDesigngetDesign as inputs to your
likelihood functionunmarkedFit objectDevelop methods specific to your unmarkedFit type for
operating on the output of your model. Like for the methods associated
with an unmarkedFrame object above, you probably will not have to
re-write all of them, but you should test them to see if they work. All
the methods associated with unmarkedFit objects are listed
in the unmarkedFit
class documentation accessible with
help("unmarkedFit-class").
Those are methods you will want to rewrite, adjusting them for your model.
getPThe getP method (defined
here) “back-transforms” the detection parameter (\(p\) the detection probability or \(\lambda\) the detection rate, depending on
the model). It returns a matrix of the estimated detection parameters.
It is called by several other methods that are useful to extract
information from the unmarkedFit object.
occu, the generic method for
unmarkedFit objects is called.gdistremovalsimulateThe generic simulate method (defined
here) calls the simulate_fit method that depends on the
class of the unmarkedFit object, which depends on the
model.
The simulate method can be used in two ways:
simulate(object = my_unmarkedFit_object)).You should test both ways with your model.
plotThis method plots the results of your model. The generic
plot method for unmarkedFit (defined
here) plot the residuals of the model.
occu, the generic method for
unmarkedFit objects is called.gdistremovalHere are methods that you should test but probably will not have to
rewrite. They are defined in the unmarkedFit.R
file, for the unmarkedFit mother class.
[backTransformcoefconfintfittedgetDatalinearCombnamesparbootnonparbootpredictprofileresidualsSEshowsummaryupdatevcovlogLikYou may also need to add specific methods to allow users to access an
attribute you added to your unmarkedFit subclass.
For example, some methods are relevant for some type of models only:
getFP for occupancy models that account for false
positivesgetB for occupancy models that account for false
positivessmoothed for colonization-extinction modelsprojected for colonization-extinction modelsNAMESPACE fileunmarkedFrame,
unmarkedFit) to the classes export hereunmarkedFrame
object to the functions export hereUsing testthat package, you need to write tests for your
unmarkedFrame function, your fitting function, and methods
described above. The tests should be fast, but cover all the key
configurations.
Write your tests in the ./tests/testthat/ folder,
creating a R file for your model. If you are using RStudio, you can run
the tests of your file easily by clicking on the “Run tests” button. You
can run all the tests by clicking on the “Test” button in the Build
pane.
You need to write the documentation files for the new classes and
functions you added. Documentation .Rd files are stored in
the man folder. Here is a documentation on how to
format your documentation.
unmarkedFrame constructor function
Depending on how much you had to add, you may also need to update existing files:
unmarkedFrame class: add them to unmarkedFrame-class.RdunmarkedFit
class: add them to unmarkedFit-class.Rd.
The same goes for your new unmarkedFitList class in unmarkedFitList-class.Rd.unmarked