#' Logit (Log Odds Ratio)
#'
#' @param x [numeric()] Value between zero and one (inclusive).
#'
#' @return [numeric()] The log of the odds ratio.
#' @export
#'
#' @examples
#' logit(0)
#' logit(0.5)
#' logit(1)
#' logit(matrix(c(0, 0.5, 0.5, 1), nrow = 2))
#'
logit <- function (x) {
# Check arguments
checkmate::assert_numeric(x, lower = 0, upper = 1)
# Return logit(x)
return(log(x / (1 - x)))
}
#' Inverse Logit
#'
#' @param y [numeric()] Finite or infinite scalar.
#'
#' @return The inverse of the log odds ratio
#' @export
#'
#' @examples
#' invlogit(Inf)
#' invlogit(0)
#' invlogit(-Inf)
#' invlogit(matrix(c(-Inf, 0, 0, Inf), nrow = 2))
#'
invlogit <- function (y) {
# Check arguments
checkmate::assert_numeric(y)
# Compute invlogit(y)
ans <- numeric(length = length(y))
inf_ind <- which(y == Inf)
fin_ind <- which(y != Inf)
ans[inf_ind] <- 1
ans[fin_ind] <- exp(y[fin_ind]) / (1 + exp(y[fin_ind]))
dim(ans) <- dim(y)
# Return invlogit(y)
return(ans)
}
#' Create Movement Rate Array
#'
#' @param p [array()] Movement parameters.
#' @param z [matrix()] Movement index..
#'
#' @return [array()] Movement rates.
#' @export
#'
#' @examples
#' # 2x2
#' x <- array(c(0.9, 0.2, 0.1, 0.8, 0.7, 0.4, 0.3, 0.6), dim = c(2, 2, 2, 1))
#' z <- array(c(0, 1, 1, 0), dim = c(2, 2))
#' p <- create_movement_parameters(x, z)
#' r <- create_movement_rates(p, z)
#' all(x - r < 1e-12)
#'
#' # 3x3 with missing adjacent rates
#' v <- c(0.9,0.1,0.3,0,0.8,0,0.1,0.1,0.7,0.6,0.2,0.6,0,0.5,0,0.4,0.3,0.4)
#' x <- array(v, dim = c(3,3,2,1))
#' z <- array(c(0,1,1,0,0,0,1,1,0), dim = c(3,3))
#' p <- create_movement_parameters(x, z)
#' r <- create_movement_rates(p, z)
#' all(x - r < 1e-12)
#'
create_movement_rates <- function (p, z) {
# Check arguments
checkmate::assert_array(p, mode = "numeric", any.missing = FALSE)
checkmate::assert_array(p, d = 3)
checkmate::assert_matrix(z, mode = "integerish", any.missing = FALSE)
checkmate::assert_numeric(z, lower = 0, upper = 1)
# Convert to transposes
tp <- aperm(p, c(2,1,3))
tz <- t(z)
# Initialize index limits
na <- nrow(tz) # Matrix tz has rows = na, and cols = na
npt <- dim(tp)[2] # Array tp has dim = c(np, npt, ng)
ng <- dim(tp)[3]
# Initialize array
r <- array(0, dim = c(na, na, npt, ng))
# Compute movement rates from movement parameters
for (mg in seq_len(ng)) {
for (cpt in seq_len(npt)) {
# Set the current parameter indexes to one
cp_num <- 1L
cp_den <- 1L
for (pa in seq_len(na)) {
# Set the denominator sum to zero for this row
den_sum <- 0
for (ca in seq_len(na)) {
if (tz[ca, pa] != 0) {
den_sum <- den_sum + exp(tp[cp_den, cpt, mg])
cp_den <- cp_den + 1
}
}
# Set the probability sum to zero
rates_sum <- 0L
# Compute the probability for ca != pa
for (ca in seq_len(na)) {
if (tz[ca, pa] != 0) {
r[pa, ca, cpt, mg] <- exp(tp[cp_num, cpt, mg]) / (1L + den_sum)
rates_sum <- rates_sum + r[pa, ca, cpt, mg]
cp_num <- cp_num + 1
}
}
# Compute the probability for pa == ca
r[pa, pa, cpt, mg] <- 1L - rates_sum
}
}
}
return(r)
}
#' Create Movement Parameter Array
#'
#' @param r [array()] Movement rates.
#' @param z [matrix()] Movement index.
#'
#' @return [array()] Movement parameters.
#' @export
#'
#' @examples
#'
#' # 2x2
#' x <- array(c(0.9, 0.2, 0.1, 0.8, 0.7, 0.4, 0.3, 0.6), dim = c(2, 2, 2, 1))
#' z <- array(c(0, 1, 1, 0), dim = c(2, 2))
#' p <- create_movement_parameters(x, z)
#' r <- create_movement_rates(p, z)
#' all(x - r < 1e-12)
#'
#' # 3x3 with missing adjacent rates
#' v <- c(0.9,0.1,0.3,0,0.8,0,0.1,0.1,0.7,0.6,0.2,0.6,0,0.5,0,0.4,0.3,0.4)
#' x <- array(v, dim = c(3,3,2,1))
#' z <- array(c(0,1,1,0,0,0,1,1,0), dim = c(3,3))
#' p <- create_movement_parameters(x, z)
#' r <- create_movement_rates(p, z)
#' all(x - r < 1e-12)
#'
create_movement_parameters <- function (r,
z = NULL) {
# Check arguments
checkmate::assert_array(r, d = 4, any.missing = FALSE)
checkmate::assert_numeric(r, lower = 0, upper = 1)
checkmate::assert_matrix(z, mode = "integerish", any.missing = FALSE)
# Initialize index limits
np <- sum(z)
na <- dim(r)[1]
npt <- dim(r)[3]
ng <- dim(r)[4]
# Check r against z
for (mg in seq_len(ng)) {
for (cpt in seq_len(npt)) {
row_sums <- rowSums(r[,, cpt, mg])
if (!all(row_sums == 1)) stop("row sums of r must all equal one\n")
for (ca in seq_len(na)) {
for (pa in seq_len(na)) {
if (pa != ca) {
if (z[pa, ca] == 0) {
if (r[pa, ca, cpt, mg] != 0) {
stop("movement rates must correspond to parameter index")
}
}
}
}
}
}
}
# Initialize array
tp <- array(0, dim = c(np, npt, ng))
# Compute movement parameters from movement rates
for (mg in seq_len(ng)) {
for (cpt in seq_len(npt)) {
# Set the current parameter index to one
cp_ind <- 1L
# Iterate over rows
for (pa in seq_len(na)) {
# Set the movement rate sum to zero
rates_sum <- 0L
# Iterate over columns
for (ca in seq_len(na)) {
if (z[pa, ca] != 0) {
rates_sum <- rates_sum + r[pa, ca, cpt, mg]
}
}
# Compute the movement parameters
for (ca in seq_len(na)) {
if (z[pa, ca] != 0) {
tp[cp_ind, cpt, mg] <- log(r[pa, ca, cpt, mg]) - log(1 - rates_sum)
cp_ind <- cp_ind + 1L
}
}
}
}
}
# Untranspose
p <- aperm(tp, c(2, 1, 3))
# Return
return(p)
}
#' Subset Numeric Vector or Matrix by Rowname, Colname, or Name
#'
#' @param x [numeric()] or [matrix()]
#' @param x_names [character()]
#'
#' @return
#'
subset_by_name <- function (x, x_names) {
if (is.numeric(x) & !is.matrix(x)) {
x[which(is.element(names(x), x_names))]
} else if (is.matrix(x)) {
rows <- which(is.element(rownames(x), x_names))
cols <- which(is.element(colnames(x), x_names))
x[rows, cols]
}
}
#' Matrix Power
#'
#' @param x [matrix()] Square numeric matrix.
#' @param pow [integer()] Matrix power.
#'
#' @return [matrix()]
#' @export
#'
#' @examples
#'
#' x <- matrix(c(1,2,3,4), nrow = 2)
#' pow <- 2
#' matrix_power(x, pow)
#'
matrix_power <- function (x, pow) {
# Check arguments
checkmate::assert_matrix(x, mode = "numeric", any.missing = FALSE)
checkmate::assert_true(nrow(x) == ncol(x))
checkmate::assert_integerish(pow, lower = 1, len = 1, any.missing = FALSE)
# Compute matrix power
x_pow <- x
for (i in seq_len(pow - 1)) x_pow <- x_pow %*% x
return(x_pow)
}
#' Create Movement Results
#'
#' @param vtp [numeric()] Vector of movement parameters in transpose order.
#' @param mtp [matrix()] Matrix of movement parameter covariances in
#' transpose order.
#' @param np [integer()] Number of movement parameters per step and group.
#' @param npt [integer()] Number of movement parameter time steps.
#' @param ng [integer()] Number of groups.
#' @param z [matrix()] Matrix index. See [mmmIndex()].
#' @param pow [integer()] Results step as a multiple of tag time step.
#' A matrix power.
#' @param draws [integer()] Number of draws from which to bootstrap
#' movement result standard errors.
#'
#' @return A [list()]
#'
create_movement_results <- function (vtp, mtp, np, npt, ng, z, pow, draws) {
# Check arguments ------------------------------------------------------------
# Vector vtp
checkmate::assert_numeric(vtp, finite = TRUE, any.missing = FALSE)
checkmate::assert_numeric(vtp, len = np * npt * ng)
# Matrix mtp
checkmate::assert_matrix(mtp, any.missing = FALSE)
checkmate::assert_true(nrow(mtp) == ncol(mtp))
# Dimensions
checkmate::assert_integerish(np, lower = 1, len = 1, any.missing = FALSE)
checkmate::assert_integerish(npt, lower = 1, len = 1, any.missing = FALSE)
checkmate::assert_integerish(ng, lower = 1, len = 1, any.missing = FALSE)
# Matrix index
checkmate::assert_matrix(z, mode = "integerish", any.missing = FALSE)
checkmate::assert_numeric(z, lower = 0, upper = 1)
checkmate::assert_true(nrow(z) == ncol(z))
# Matrix power: result step as a multiple of tag step
checkmate::assert_integerish(pow, lower = 1, len = 1, any.missing = FALSE)
# Number of bootstrapping draws
checkmate::assert_integerish(draws, lower = 1, len = 1, any.missing = FALSE)
# Create movement parameters -------------------------------------------------
tp_fit <- array(vtp, dim = c(np, npt, ng))
p_fit <- aperm(tp_fit, c(2, 1, 3))
# Create movement rates ------------------------------------------------------
r_fit <- create_movement_rates(p = p_fit, z = z)
r_results <- array(0, dim = dim(r_fit))
for (cpt in seq_len(npt)) {
for (mg in seq_len(ng)) {
r_results[, , cpt, mg] <- matrix_power(r_fit[, , cpt, mg], pow)
}
}
# Create movement rate standard errors ---------------------------------------
# Initialize
r_draws <- array(0, dim = c(dim(r_results), draws))
# Perform draws: each row is one draw in vector transpose order
mtp_draws <- MASS::mvrnorm(
n = draws,
mu = vtp,
Sigma = mtp,
empirical = FALSE
)
# Populate r_draws
for (i in seq_len(draws)) {
# Create parameter array
tp <- array(mtp_draws[i, ], dim = c(np, npt, ng))
p <- aperm(tp, c(2, 1, 3))
# Create movement rates
r_draws[, , , , i] <- create_movement_rates(p = p, z = z)
}
# Convert to r_result_draws
r_results_draws <- array(0, dim = c(dim(r_results), draws))
r_results_se <- array(0, dim = dim(r_results))
for (i in seq_len(draws)) {
for (cpt in seq_len(npt)) {
for (mg in seq_len(ng)) {
r_results_draws[, , cpt, mg, i] <-
matrix_power(r_draws[, , cpt, mg, i], pow)
}
}
}
# Summarize SE
na <- nrow(z)
for (mg in seq_len(ng)) {
for (cpt in seq_len(npt)) {
for (ca in seq_len(na)) {
for (pa in seq_len(na)) {
r_results_se[pa, ca, cpt, mg] <-
stats::sd(r_results_draws[pa, ca, cpt, mg, ], na.rm = TRUE)
}
}
}
}
# Create movement results data frame -----------------------------------------
# Initialize
movement_results <- matrix(0, nrow = prod(dim(r_results)), ncol = 6L)
row_ind <- 1L
# Populate
for (mg in seq_len(ng)) {
for (cpt in seq_len(npt)) {
for (pa in seq_len(na)) {
for (ca in seq_len(na)) {
movement_results[row_ind, 1] <- pa
movement_results[row_ind, 2] <- ca
movement_results[row_ind, 3] <- cpt
movement_results[row_ind, 4] <- mg
movement_results[row_ind, 5] <- r_results[pa, ca, cpt, mg]
movement_results[row_ind, 6] <- r_results_se[pa, ca, cpt, mg]
row_ind <- row_ind + 1L
}
}
}
}
# Set column names
dim_names <- c("Area_From", "Area_To", "Result_Step", "Group")
res_names <- c("Estimate", "SE")
colnames(movement_results) <- c(dim_names, res_names)
# Convert to data frame
movement_results <- as.data.frame(movement_results)
# Rename
names(p_fit) <- NULL
names(r_fit) <- NULL
names(r_results) <- NULL
names(r_results_se) <- NULL
# Return list of results -----------------------------------------------------
return(list(
movement_rate = movement_results,
p_fit = p_fit,
r_fit = r_fit,
r_results = r_results,
r_results_se = r_results_se
))
}
#' Create Natural Mortality Results
#'
#' @param logit_exp_neg_m [numeric()] Scalar estimate.
#' @param logit_exp_neg_m_se [numeric()] Scalar estimate.
#' @param results_step [integer()] Results step as multiple of tag step.
#' @param estimate [logical()] Estimate natural mortality?
#'
#' @return [list()]
#'
create_mortality_results <- function (logit_exp_neg_m,
logit_exp_neg_m_se,
results_step,
estimate) {
if (estimate) {
# Estimate
m_fit <- -log(invlogit(logit_exp_neg_m))
m_results <- m_fit * results_step
# Standard error
logit_exp_neg_m_draws <- stats::rnorm(
1000,
logit_exp_neg_m,
logit_exp_neg_m_se
)
m_draws <- -log(invlogit(logit_exp_neg_m_draws))
m_results_se <- stats::sd(m_draws * results_step, na.rm = TRUE)
# Rename
names(m_fit) <- NULL
names(m_results) <- NULL
names(m_results_se) <- NULL
} else {
m_fit <- NULL
m_results <- NULL
m_results_se <- NULL
}
# Data frame
natural_mortality <- data.frame(Estimate = m_results, SE = m_results_se)
# Return
return(list(
natural_mortality = natural_mortality,
m_fit = m_fit,
m_results = m_results,
m_results_se = m_results_se
))
}
#' Create Fishing Rate Results
#'
#' @param vlogit_exp_neg_tf [numeric()] Vector estimates.
#' @param mlogit_exp_neg_tf_cov [matrix()] Covariances.
#' @param results_step [integer()] Results step as multiple of tag step.
#' @param nft [integer()] Number of fishing rate time steps.
#' @param nfa [integer()] Number of fishing rate areas.
#' @param estimate [logical()] Estimate fishing mortality rate(s)?
#'
#' @return [list()]
#'
create_fishing_results <- function (vlogit_exp_neg_tf,
mlogit_exp_neg_tf_cov,
results_step,
nft,
nfa,
estimate) {
if (estimate) {
# Estimate
vtf_fit <- -log(invlogit(vlogit_exp_neg_tf))
tf_fit <- matrix(vtf_fit, nrow = nfa, ncol = nft)
f_fit <- t(tf_fit)
f_results <- f_fit * results_step
# Standard error
mvlogit_exp_neg_tf_draws <- MASS::mvrnorm(
n = 1000,
mu = vlogit_exp_neg_tf,
Sigma = mlogit_exp_neg_tf_cov
)
# Untransform
mvtf_draws <- -log(invlogit(mvlogit_exp_neg_tf_draws))
# Compute SE
vtf_results_se <- apply(mvtf_draws * results_step, 2, stats::sd, na.rm = TRUE)
tf_results_se <- matrix(vtf_results_se, nrow = nfa, ncol = nft)
f_results_se <- t(tf_results_se)
# Rename
names(f_fit) <- NULL
names(f_results) <- NULL
names(f_results_se) <- NULL
# Initialize
fishing_rate <- matrix(0, nrow = prod(dim(f_results)), ncol = 4L)
row_ind <- 1L
# Populate
for (cfa in seq_len(nfa)) {
for (cft in seq_len(nft)) {
fishing_rate[row_ind, 1] <- cfa
fishing_rate[row_ind, 2] <- cft
fishing_rate[row_ind, 3] <- f_results[cft, cfa]
fishing_rate[row_ind, 4] <- f_results_se[cft, cfa]
row_ind <- row_ind + 1L
}
}
# Set column names
dim_names <- c("Fish_area", "Fish_Step")
res_names <- c("Estimate", "SE")
colnames(fishing_rate) <- c(dim_names, res_names)
# Convert to data frame
fishing_rate <- as.data.frame(fishing_rate)
} else {
f_fit <- NULL
f_results <- NULL
f_results_se <- NULL
# Data frame
fishing_rate <- data.frame(
Fish_Area = NULL,
Fish_Step = NULL,
Estimate = f_results,
SE = f_results_se)
}
# Return
return(list(
fishing_rate = fishing_rate,
f_fit = f_fit,
f_results = f_results,
f_results_se = f_results_se
))
}
#' Create Fishing Mortality Bias Results
#'
#' @param log_b [numeric()] Vector.
#' @param log_b_cov [matrix()] Covariances.
#' @param estimate [logical()] Estimate or return NULL.
#'
#' @return [list()]
#'
create_bias_results <- function (log_b,
log_b_cov,
estimate) {
if (estimate) {
# Estimate
b_fit <- exp(log_b)
b_results <- b_fit
# Compute draws
log_b_draws <- MASS::mvrnorm(
n = 1000,
mu = log_b,
Sigma = log_b_cov
)
# Untransform
b_draws <- exp(log_b_draws)
# Compute SE
b_results_se <- apply(b_draws, 2, stats::sd, na.rm = TRUE)
# Rename
names(b_fit) <- NULL
names(b_results) <- NULL
names(b_results_se) <- NULL
} else {
b_fit <- NULL
b_results <- NULL
b_results_se <- NULL
}
# Data frame
fishing_bias <- data.frame(Estimate = b_results, SE = b_results_se)
# Return
return(list(
fishing_bias = fishing_bias,
b_fit = b_fit,
b_results = b_results,
b_results_se = b_results_se
))
}
#' Create Dispersion Results
#'
#' @param log_k [numeric()] Scalar estimate.
#' @param log_k_se [numeric()] Scalar estimate.
#' @param estimate [logical()] Estimate negative binomial dispersion?
#'
#' @return [list()]
#'
create_dispersion_results <- function (log_k,
log_k_se,
estimate) {
if (estimate) {
# Estimate
k_fit <- exp(log_k)
k_results <- k_fit
# Compute SE
log_k_draws <- stats::rnorm(1000, log_k, log_k_se)
k_results_se <- stats::sd(exp(log_k_draws), na.rm = TRUE)
# Rename
names(k_fit) <- NULL
names(k_results) <- NULL
names(k_results_se) <- NULL
} else {
k_fit <- NULL
k_results <- NULL
k_results_se <- NULL
}
# Data frame
dispersion <- data.frame(Estimate = k_results, SE = k_results_se)
# Return
return(list(
dispersion = dispersion,
k_fit = k_fit,
k_results = k_results,
k_results_se = k_results_se
))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.