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:
showClass("unmarkedFrame")## Class "unmarkedFrame" [package "unmarked"]
##
## Slots:
##
## Name: y obsCovs siteCovs mapInfo
## Class: matrix optionalDataFrame optionalDataFrame optionalMapInfo
##
## Name: obsToY
## Class: optionalMatrix
##
## Known Subclasses:
## Class "unmarkedMultFrame", directly
## Class "unmarkedFrameDS", directly
## Class "unmarkedFrameOccu", directly
## Class "unmarkedFrameOccuFP", directly
## Class "unmarkedFrameOccuMulti", directly
## Class "unmarkedFramePCount", directly
## Class "unmarkedFrameMPois", directly
## Class "unmarkedFrameOccuCOP", directly
## Class "unmarkedFrameOccuMS", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameOccuTTD", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameG3", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFramePCO", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameGDR", by class "unmarkedMultFrame", distance 2
## Class "unmarkedFrameGMM", by class "unmarkedMultFrame", distance 3
## Class "unmarkedFrameGDS", by class "unmarkedMultFrame", distance 3
## Class "unmarkedFrameGPC", by class "unmarkedMultFrame", distance 3
## Class "unmarkedFrameGOccu", by class "unmarkedMultFrame", distance 3
## Class "unmarkedFrameMMO", by class "unmarkedMultFrame", distance 4
## Class "unmarkedFrameDSO", by class "unmarkedMultFrame", distance 4
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.
coordinatesgetYnumSitesnumYobsCovsobsCovs<-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.
[backTransformcoefconfintfittedgetDatahessianlinearCombmlenamesnllFunparbootnonparbootpredictprofileresidualssampleSizeSEshowsummaryupdatevcovlogLikLRTYou 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
unmarkedFit class to predict-methods.RdgetP method for the signature of you unmarkedFitList object in getP-methods.Rd.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