Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update recruitment, priors #42

Merged
merged 49 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9e2dba6
add johns orcid
sebdalgarno Apr 5, 2024
dd2708d
move analytical methods to methods vignette and move bboufit details …
sebdalgarno Apr 5, 2024
1ac5b7b
fix predict ML for fixed with missing first year
sebdalgarno Apr 5, 2024
e113743
add john orcid
sebdalgarno Apr 5, 2024
0fce2e4
loosen priors on fixed year effect survival, fixes #38
sebdalgarno Apr 5, 2024
353bef9
use sd of 2 for trend since year is scaled
sebdalgarno Apr 6, 2024
430b93f
use rounder number for recruitment b0 prior
sebdalgarno Apr 6, 2024
cb1a8b1
loosen recruitment prior (especially for lower bound)
sebdalgarno Apr 6, 2024
af50e26
add vignette on priors
sebdalgarno Apr 6, 2024
1879640
add example of bayes/ML and fixed/random
sebdalgarno Apr 6, 2024
a406489
improve priors wording
sebdalgarno Apr 6, 2024
2b2e33d
add dplyr to suggests for vignettes
sebdalgarno Apr 6, 2024
3a5c914
minor wording changes to methods vignette
sebdalgarno Apr 7, 2024
001341a
add dplyr to suggests
sebdalgarno Apr 8, 2024
5722989
add dplyr funs to namespace
sebdalgarno Apr 8, 2024
d37f1c6
add predict_calf_cow and change predict_recruitment to decesare recru…
sebdalgarno Apr 8, 2024
c89ac15
only add bAnnual[1] if year not excluded
sebdalgarno Apr 8, 2024
fcb74c8
ensure that se join by correct term
sebdalgarno Apr 8, 2024
b167d23
document
sebdalgarno Apr 8, 2024
29df8e9
rebuild data with new priors and add fixed_ml for testing correct bAn…
sebdalgarno Apr 8, 2024
a9d2a5a
update tests and snapshots
sebdalgarno Apr 8, 2024
9d348da
ensure CaribouYear in order in case where year level intercept shuffled
sebdalgarno Apr 9, 2024
8a8f427
add decesare ref to documentation and match terminology in bbouretro,…
sebdalgarno Apr 9, 2024
75dbb0b
add sex_ratio arg for use in decesare recxruitment calculations
sebdalgarno Apr 9, 2024
01f85b5
use special method to change intercept for ML fixed year models, sign…
sebdalgarno Apr 9, 2024
4c9e844
move calf-cow text
sebdalgarno Apr 11, 2024
8de6d69
add calf-cow prediction tests
sebdalgarno Apr 11, 2024
afeba3e
pass sex_ratio through generic predict recruitment
sebdalgarno Apr 11, 2024
8597ce1
trend model does adjusted recruitment prediction
sebdalgarno Apr 11, 2024
d52bf46
year trend recruitment y-axis title without calves/adult female
sebdalgarno Apr 11, 2024
e8708f4
add sex ratio tests for lambda and pop change
sebdalgarno Apr 11, 2024
12d2d80
add sex ratio arg to internal functions
sebdalgarno Apr 11, 2024
796d30a
use inherited params for survival/recruitment
sebdalgarno Apr 11, 2024
8b3f0c3
remove smart_intercept arg no longer used
sebdalgarno Apr 11, 2024
aae5c1a
update snapshots
sebdalgarno Apr 12, 2024
475d1c0
add magrittr
sebdalgarno Apr 12, 2024
75b7835
document
sebdalgarno Apr 12, 2024
b2ffb3b
use binomial model aggregated by year
sebdalgarno Apr 13, 2024
bedcb02
update priors to reflect binomial model
sebdalgarno Apr 13, 2024
c54819c
update survival priors in vignette model
sebdalgarno Apr 13, 2024
38c5560
update docs to new binomical recruitment model
sebdalgarno Apr 13, 2024
55edfb2
update to describe binomial recruitment model instead of poisson
sebdalgarno Apr 13, 2024
9dfaaa0
update recruitment priors now on logit scale
sebdalgarno Apr 13, 2024
aa2920a
log-odds scale now not log
sebdalgarno Apr 13, 2024
357e31b
update data and snapshots
sebdalgarno Apr 13, 2024
9d2c6dc
chceks pass dplyr global vars
sebdalgarno Apr 13, 2024
38cfa4a
run styler
sebdalgarno Apr 14, 2024
d4b9419
run linter
sebdalgarno Apr 14, 2024
52f73a3
minor correction to year_start arg documentation
sebdalgarno Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Authors@R: c(
comment = c(ORCID = "0000-0002-3658-4517")),
person("Joe", "Thorley", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0002-7683-4592")),
person("John", "Boulanger", role = "aut"),
person("John", "Boulanger", role = "aut",
comment = c(ORCID = "0000-0001-8222-1445")),
person("Ayla", "Pearson", , "[email protected]", role = "aut"),
person(given = "Environment and Climate Change Canada",
role = "cph")
Expand All @@ -22,10 +23,12 @@ Depends:
Imports:
bboudata,
chk,
dplyr,
generics,
ggplot2,
glue,
lifecycle,
magrittr,
mcmcderive,
mcmcr,
newdata,
Expand Down
6 changes: 6 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export(bb_plot_year_recruitment)
export(bb_plot_year_survival)
export(bb_plot_year_trend_recruitment)
export(bb_plot_year_trend_survival)
export(bb_predict_calf_cow_ratio)
export(bb_predict_growth)
export(bb_predict_lambda)
export(bb_predict_population_change)
Expand Down Expand Up @@ -95,9 +96,14 @@ export(samples)
export(tidy)
import(chk)
import(glue)
import(magrittr)
import(nimble)
importFrom(bboudata,bbd_chk_data_recruitment)
importFrom(bboudata,bbd_chk_data_survival)
importFrom(dplyr,arrange)
importFrom(dplyr,bind_rows)
importFrom(dplyr,left_join)
importFrom(dplyr,tibble)
importFrom(generics,augment)
importFrom(generics,glance)
importFrom(generics,tidy)
Expand Down
12 changes: 12 additions & 0 deletions R/data-recruitment.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ data_clean_recruitment <- function(data, quiet = FALSE) {
data_prep_recruitment <- function(data, year_start) {
data$CowsBulls <- data$Cows + data$Bulls
data$Year <- caribou_year(data$Year, data$Month, year_start = year_start)
data <-
data %>%
dplyr::group_by(Year) %>%
dplyr::summarize(
Cows = sum(.data$Cows),
CowsBulls = sum(.data$CowsBulls),
UnknownAdults = sum(.data$UnknownAdults),
Yearlings = sum(.data$Yearlings),
Calves = sum(.data$Calves),
PopulationName = dplyr::first(.data$PopulationName)
) %>%
dplyr::ungroup()
data$Annual <- factor(data$Year)

data
Expand Down
22 changes: 17 additions & 5 deletions R/data-survival.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,28 @@ data_clean_survival <- function(data, quiet) {
data
}

data_prep_survival <- function(data, include_uncertain_morts, year_start) {
data_prep_survival <- function(data, include_uncertain_morts,
year_start) {
data$Mortalities <- data$MortalitiesCertain
if (include_uncertain_morts) {
data$Mortalities <- data$Mortalities + data$MortalitiesUncertain
}
data$Year <- caribou_year(data$Year, data$Month, year_start = year_start)
data$Annual <- factor(data$Year)

# leaves month but sets factor levels to be caribou month for model
nmonth <- length(unique(data$Month))
data$Month <- factor(data$Month, levels = month_levels(year_start, n = nmonth))
data$Mortalities <- data$MortalitiesCertain
if (include_uncertain_morts) {
data$Mortalities <- data$Mortalities + data$MortalitiesUncertain
}

data
}

data_adjust_intercept <- function(data) {
year_b0 <- year_intercept(data)
levels <- unique(data$Year)
levels <- levels[levels != year_b0]
levels <- c(year_b0, levels)
data$Annual <- factor(data$Year, levels = levels)
data
}

Expand Down
4 changes: 2 additions & 2 deletions R/derived.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ derived_expr_recruitment <- function(fit, year) {
lik <- extract_lik(fit)
}
paste0("for(i in 1:length(Annual)) {
log(prediction[i]) <- ", lik, "\n}")
logit(prediction[i]) <- ", lik, "\n}")
}

derived_expr_recruitment_trend <- function() {
"for(i in 1:length(Annual)) {
log(prediction[i]) <- b0 + bYear * Year[i]\n}"
logit(prediction[i]) <- b0 + bYear * Year[i]\n}"
}

derived_expr_survival_trend <- function() {
Expand Down
29 changes: 14 additions & 15 deletions R/fit-recruitment.R
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#' Fit Recruitment Model
#'
#' Fit heirarchical Bayesian recruitment model using Nimble.
#'
#'
#' If the number of years is > `min_random_year`, a fixed-effects model is fit.
#' Otherwise, a mixed-effects model is fit with random intercept for each year.
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' will be fit with year as a continuous effect and a random intercept for each year.
#'
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' will be fit with year as a continuous effect and a random intercept for each year.
#'
#' The start month of the Caribou year can be adjusted with `year_start`.
#'
#' @inheritParams params
Expand Down Expand Up @@ -94,18 +94,18 @@ bb_fit_recruitment <- function(
#' Fit Recruitment Model with Maximum Likelihood
#'
#' Fit recruitment model with Maximum Likelihood using Nimble Laplace Approximation.
#'
#'
#' If the number of years is > `min_random_year`, a fixed-effects model is fit.
#' Otherwise, a mixed-effects model is fit with random intercept for each year.
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' will be fit with year as a continuous effect and a random intercept for each year.
#'
#' Year effect can be excluded with `exclude_year`. This can be useful if the ML model is failing to converge.
#'
#'
#' The start month of the Caribou year can be adjusted with `year_start`.
#'
#'
#' @inheritParams params
#' @return A list of the Nimble model object and Maximum Likelihood output with estimates and standard errors on the transformed scale.
#' @export
Expand Down Expand Up @@ -139,10 +139,9 @@ bb_fit_recruitment_ml <- function(
data <- model_data_recruitment(data, year_start = year_start, quiet = quiet)
year_random <- data$datal$nAnnual >= min_random_year
if (!year_random && year_trend) {
if(!quiet) message_trend_fixed()
if (!quiet) message_trend_fixed()
}

priors <- priors_recruitment()
model <- model_recruitment(
data = data$datal,
year_random = year_random,
Expand All @@ -164,7 +163,7 @@ bb_fit_recruitment_ml <- function(

convergence_fail <- ml_converge_fail(fit) || ml_se_fail(fit)
if (convergence_fail) {
if(!quiet) message_convergence_fail()
if (!quiet) message_convergence_fail()
}

fit <- fit$result
Expand Down
48 changes: 28 additions & 20 deletions R/fit-survival.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ ml_se_fail <- function(x) {
#' Fit Survival Model
#'
#' Fits hierarchical Bayesian survival model using Nimble.
#'
#'
#' If the number of years is > `min_random_year`, a fixed-effects model is fit.
#' Otherwise, a mixed-effects model is fit with random intercept for each year.
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' will be fit with year as a continuous effect and a random intercept for each year.
#'
#' The model is always fit with random intercept for each month.
#'
#'
#' The start month of the Caribou year can be adjusted with `year_start`.
#'
#' @inheritParams params
Expand Down Expand Up @@ -107,20 +107,20 @@ bb_fit_survival <- function(data,
#' Fit Survival Model with Maximum Likelihood
#'
#' Fits hierarchical survival model with Maximum Likelihood using Nimble Laplace approximation.
#'
#'
#' If the number of years is > `min_random_year`, a fixed-effects model is fit.
#' Otherwise, a mixed-effects model is fit with random intercept for each year.
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' If `year_trend` is TRUE and the number of years is > `min_random_year`, the model
#' will be fit with year as a continuous effect (i.e. trend) and no fixed effect of year.
#' If `year_trend` is TRUE and the number of years is <= `min_random_year`, the model
#' will be fit with year as a continuous effect and a random intercept for each year.
#'
#' The model is always fit with random intercept for each month.
#'
#'
#' Year effect can be excluded with `exclude_year`. This can be useful if the ML model is failing to converge.
#'
#'
#' The start month of the Caribou year can be adjusted with `year_start`.
#'
#'
#' @inheritParams params
#' @return A list of the Nimble model object and Maximum Likelihood output with estimates and standard errors on the transformed scale.
#' @export
Expand Down Expand Up @@ -150,14 +150,22 @@ bb_fit_survival_ml <- function(data,
chk_null_or(inits, vld = vld_named)
chk_flag(quiet)

data <-
model_data_survival(data,
include_uncertain_morts = include_uncertain_morts,
year_start = year_start, quiet = quiet
)
year_random <- data$datal$nAnnual >= min_random_year
# special treatment of intercept for ML fixed
data <- data_clean_survival(data, quiet = quiet)
data <- data_prep_survival(data,
include_uncertain_morts = include_uncertain_morts,
year_start = year_start
)
year_random <- length(unique(data$Year)) >= min_random_year
if (!year_random) {
data <- data_adjust_intercept(data)
}

datal <- data_list_survival(data)
data <- list(datal = datal, data = data)

if (!year_random && year_trend && !exclude_year) {
if(!quiet) message_trend_fixed()
if (!quiet) message_trend_fixed()
}

model <-
Expand All @@ -178,7 +186,7 @@ bb_fit_survival_ml <- function(data,

convergence_fail <- ml_converge_fail(fit) || ml_se_fail(fit)
if (convergence_fail) {
if(!quiet) message_convergence_fail()
if (!quiet) message_convergence_fail()
}

fit <- fit$result
Expand Down
18 changes: 9 additions & 9 deletions R/model-recruitment.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ model_data_recruitment <- function(data, year_start = year_start, quiet) {
#' Build Nimble recruitment model.
#'
#' This is for use by developers.
#'
#'
#' @inheritParams params
#' @param demographic_stochasticity A flag indicating whether to include demographic_stochasticity in the recruitment model.
#' @export
Expand Down Expand Up @@ -69,16 +69,16 @@ model_recruitment <-
if (year_trend) {
if (year_random) {
for (i in 1:nObs) {
log(eRecruitment[i]) <- b0 + bAnnual[Annual[i]] + bYear * Year[i]
logit(eRecruitment[i]) <- b0 + bAnnual[Annual[i]] + bYear * Year[i]
}
} else {
for (i in 1:nObs) {
log(eRecruitment[i]) <- b0 + bYear * Year[i]
logit(eRecruitment[i]) <- b0 + bYear * Year[i]
}
}
} else {
for (i in 1:nObs) {
log(eRecruitment[i]) <- b0 + bAnnual[Annual[i]]
logit(eRecruitment[i]) <- b0 + bAnnual[Annual[i]]
}
}

Expand All @@ -95,9 +95,9 @@ model_recruitment <-
}
} else {
for (i in 1:nObs) {
FemaleYearlings[i] <- yearling_female_proportion * Yearlings[i]
FemaleYearlings[i] <- round(yearling_female_proportion * Yearlings[i])
OtherAdultsFemales[i] <-
adult_female_proportion * UnknownAdults[i]
round(adult_female_proportion * UnknownAdults[i])
}
}

Expand All @@ -107,7 +107,7 @@ model_recruitment <-
# in original model because max cannot be used with ML
((FemaleYearlings[i] + Cows[i] + OtherAdultsFemales[i]) < 1) +
FemaleYearlings[i] + Cows[i] + OtherAdultsFemales[i]
Calves[i] ~ dpois(eRecruitment[i] * AdultsFemales[i])
Calves[i] ~ dbin(eRecruitment[i], AdultsFemales[i])
}
})

Expand All @@ -122,10 +122,10 @@ model_recruitment <-
buildDerivs = TRUE,
name = "bboumodel_recruitment"
)

# reset to user
nimbleOptions(verbose = verbose)
nimbleOptions(enableDerivs = enable_derivs)

model
}
13 changes: 8 additions & 5 deletions R/model-survival.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
model_data_survival <- function(data, include_uncertain_morts, year_start, quiet) {
model_data_survival <- function(data,
include_uncertain_morts,
year_start,
quiet) {
data <- data_clean_survival(data, quiet = quiet)
data <- data_prep_survival(data,
include_uncertain_morts = include_uncertain_morts,
Expand All @@ -11,7 +14,7 @@ model_data_survival <- function(data, include_uncertain_morts, year_start, quiet
#' Build Nimble survival model.
#'
#' This is for use by developers.
#'
#'
#' @inheritParams params
#' @param build_derivs A flag indicating whether to build derivatives Laplace approximation.
#' @export
Expand Down Expand Up @@ -94,16 +97,16 @@ model_survival <- function(data,
enable_derivs <- nimbleOptions("enableDerivs")
nimbleOptions(verbose = FALSE)
nimbleOptions(enableDerivs = TRUE)

model <- nimbleModel(code,
constants = constants,
buildDerivs = build_derivs,
name = "bboumodel_survival"
)

# reset to user
nimbleOptions(verbose = verbose)
nimbleOptions(enableDerivs = enable_derivs)

model
}
3 changes: 2 additions & 1 deletion R/namespace.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#' @import chk glue nimble
#' @import chk glue nimble magrittr
#' @importFrom scales percent
#' @importFrom rescale rescale
#' @importFrom dplyr arrange tibble bind_rows left_join
#' @importFrom purrr quietly map map_dbl map_lgl
#' @importFrom stats setNames update median coef predict nobs plogis runif qnorm logLik
#' @importFrom ggplot2 autoplot .data ggplot aes geom_pointrange geom_hline scale_x_continuous scale_x_discrete scale_y_continuous expand_limits xlab geom_line geom_ribbon
Expand Down
2 changes: 1 addition & 1 deletion R/nimble.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ run_nimble_ml <- function(model, inits, prior_inits, quiet) {
cmodel <- compileNimble(model, resetFunctions = TRUE)
params <- setupMargNodes(model)$paramNodes
chk_subset(names(inits), params, x_name = "Names in `inits`")

# need to deal with special case when estimating adult_female_proportion
# nimble does not guess default param nodes correctly
cows <- map_lgl(params, function(x) grepl("Cows", x))
Expand Down
Loading