The FishSET R package provides a robust framework for discrete choice
modeling (DCM), utilizing RTMB (R Template Model Builder)
for automatic differentiation and optimized parameter estimation. While
functions like fishset_design() and
fishset_fit() offer a solid foundation for conditional
logit and expected profit models, we recognize that specialized research
often requires custom model structures.
To maximize computational performance and ensure compatibility with
downstream FishSET tools (like our policy function and database
loggers), custom models must be integrated directly into the
RTMB framework. We encourage users to develop their own
objective functions and submit them to be merged into the official
FishSET toolkit.
This vignette outlines the workflow for developing a custom model by
leveraging existing FishSET data pipelines and writing an
RTMB negative log-likelihood function. Reach out to our
team at [email protected] with
any questions.
Fork the FishSET repo and clone the forked repository to your computer. More information on “forking” repositories and the GitHub workflow can be found here.
Open the FishSET_RPackage.Rproj file.
Develop your custom data processing and RTMB
objective function following the steps below.
Modify fishset_fit.R and
fishset_design.R locally to include your model.
Review and test code on local datasets.
Commit, push changes, and submit a pull request.
Rather than formatting data manually, rely on the built-in
format_model_data() function to aggregate your main
dataset, distance matrices, expectations, and gridded data.
This function saves the combined dataset as a .qs2 or
.rds file in the Models/FormattedData
directory inside your project folder. Load this dataset into your
environment to begin designing your model matrix.
The fishset_fit() function expects a specific list
structure, of class fishset_design, to perform estimations.
If your model requires predictors or matrix shapes that the standard
fishset_design() function cannot currently generate, write
a custom data processing script that builds a list mirroring this
required structure.
Your design object must contain the following elements:
y: A numeric vector indicating the binary choice
variable (0 or 1).
X: A sparse model matrix containing your formatted
predictors.
settings: A list containing dimensions such as
N_obs (number of observations), J_alts (number
of alternatives), and K_vars (number of
parameters).
ids: A list containing unique observation IDs and
zone identifiers to be used for post-estimation predictions.
The core of FishSET’s speed relies on RTMB::MakeADFun
and stats::nlminb. To integrate your model, you must write
a negative log-likelihood (NLL) function compatible with this
framework.
Inside fishset_fit(), parameter estimation relies on two
main components passed to RTMB:
data_list: A list containing all known data
(X matrix, observations, dimensions).
start_pars: A list of initial parameter values to be
optimized (e.g., betas).
Your custom function must extract these elements using
RTMB::getAll() and calculate the NLL.
# Example custom model template for an RTMB NLL function
nll_func_custom <- function(pars) {
# Unpack data_list and parameters into the function environment
RTMB::getAll(data_list, pars)
# Perform matrix multiplication (e.g., sparse design matrix %*% parameters)
v <- X %*% betas
# Extract utility of chosen alternatives
v_chosen <- v[chosen_lin_idx]
# Reshape utility vector for log-sum-exp calculations
dim(v) <- c(J_alts, N_obs)
# Calculate log-sum-exp (consider robust numeric scaling if necessary)
log_sum_exp <- log(RTMB::colSums(exp(v)))
# Calculate the negative log-likelihood
nll <- -sum(v_chosen - log_sum_exp)
return(nll)
}Important Note: When writing an RTMB
function, you must use RTMB compatible math functions
(e.g., RTMB::dnorm, RTMB::rowSums) rather than
standard base R variants to ensure automatic differentiation works
properly.
Once you have a working design object and an RTMB
objective function, you can integrate your code into the package.
Modify fishset_fit.R: Add a new
if/else block within the fishset_fit()
function to handle your custom model type. Set up your unique
data_list and start_pars, and define your
custom nll_func within this block.
Standardize Outputs: Ensure your code allows
RTMB::MakeADFun and stats::nlminb to run,
producing a result formatted as class fishset_fit. This
guarantees your model outputs a coefficient table, diagnostics, AIC/BIC,
and predicted probabilities that seamlessly integrate with the project
database.
Submit a Pull Request: Give the Pull Request an informative name and provide a brief description of the mathematical structure of your model. Our team will review the code and notify you of any requested changes prior to merging.