-
Notifications
You must be signed in to change notification settings - Fork 2
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
Get initial parameter estimates and tweak initial parameter estimates #635
Conversation
…ith other relevant information - The information returned from this function will be needed for the new tweak/jitter function. It currently relies on internal `nmrec` functions, and likely needs to be reworked to be more readable. - I think a function like this belongs in `nmrec`, but wanted to develop a prototype in `bbr` to facilitate the conversation in terms of what information I need - In the end, we want to export a function *similar* to what I have so far, but with improved formatting; perhaps as a table, similar to `param_estimates()`. The `bbr` function could be a wrapper of the `nmrec` function we develop, but I think the core work should be done in `nmrec`
Examples so far: Setupsource("/data/Projects/package_dev/bbr/tests/testthat/setup-workflow-ref.R", echo=FALSE)
MODEL_DIR_C <- system.file("model", "nonmem", "complex", package = "bbr") Example modelsThese are the examples that have been tested thus far .mod <- MOD1
.mod <- read_model(file.path(MODEL_DIR_C, "1001"))
.mod <- read_model(file.path(MODEL_DIR_C, "example2_saemimp")) Example outputBase Model. Bounds must be tabulated so that we can respect them when tweaking the initial estimates (see conversation here) MOD1> .mod <- MOD1
> get_param_inits(.mod)
$theta
# A tibble: 5 × 3
low init index
<chr> <chr> <int>
1 0 2 1
2 0 3 2
3 0 10 3
4 NA 0.02 4
5 NA 1 5
$omega
$omega$matrices
$omega$matrices[[1]]
[,1] [,2]
[1,] 0.05 0.0
[2,] 0.00 0.2
$omega$fixed
$omega$fixed[[1]]
[1] FALSE
$sigma
$sigma$matrices
$sigma$matrices[[1]]
[,1]
[1,] 1
$sigma$fixed
$sigma$fixed[[1]]
[1] TRUE Model with multiple records: here we create a combined matrix, which will facilitate passing jittered values to 1001> .mod <- read_model(file.path(MODEL_DIR_C, "1001"))
> get_param_inits(.mod)
$theta
# A tibble: 6 × 2
init index
<chr> <int>
1 -0.574219127214817 1
2 5.67154052944669 2
3 1.03568637508119 3
4 0.241769673098703 4
5 -11.3632385211334 5
6 5.11272713931817 6
$omega
$omega$matrices
$omega$matrices[[1]]
[,1]
[1,] 0.09
$omega$matrices[[2]]
[,1] [,2] [,3]
[1,] 0.09 0.00 0.00
[2,] 0.01 0.09 0.00
[3,] 0.01 0.01 0.09
$omega$fixed
$omega$fixed[[1]]
[1] FALSE
$omega$fixed[[2]]
[1] FALSE
$omega$full_matrix
[,1] [,2] [,3] [,4]
[1,] 0.09 0.00 0.00 0.00
[2,] 0.00 0.09 0.00 0.00
[3,] 0.00 0.01 0.09 0.00
[4,] 0.00 0.01 0.01 0.09
$sigma
$sigma$matrices
$sigma$matrices[[1]]
[,1] [,2]
[1,] 0.04 0.00
[2,] 0.00 0.04
$sigma$fixed
$sigma$fixed[[1]]
[1] FALSE Note: this model as prior blocks, so the output here is technically incorrect, or at least lacking in terms of differentiating between actual records and priors. Additional logic would be needed to filter these out or error if the expected length wasnt found example2_saemimp> .mod <- read_model(file.path(MODEL_DIR_C, "example2_saemimp"))
> get_param_inits(.mod)
$theta
# A tibble: 12 × 3
init fixed index
<chr> <chr> <int>
1 0.7 NA 1
2 0.7 NA 2
3 2 NA 3
4 2.0 NA 4
5 0.7 NA 5
6 0.7 NA 6
7 2.0 NA 7
8 2.0 NA 8
9 0.7 NA 9
10 0.7 NA 10
11 0.3 NA 11
12 4 TRUE 12
$omega
$omega$matrices
$omega$matrices[[1]]
[,1] [,2] [,3] [,4]
[1,] 0.500 0.000 0.000 0.0
[2,] 0.001 0.500 0.000 0.0
[3,] 0.001 0.001 0.500 0.0
[4,] 0.001 0.001 0.001 0.5
$omega$matrices[[2]]
[,1] [,2] [,3] [,4]
[1,] 0.01 0.00 0.00 0.00
[2,] 0.00 0.01 0.00 0.00
[3,] 0.00 0.00 0.01 0.00
[4,] 0.00 0.00 0.00 0.01
$omega$fixed
$omega$fixed[[1]]
[1] FALSE
$omega$fixed[[2]]
[1] TRUE
$omega$full_matrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.500 0.000 0.000 0.0 0.00 0.00 0.00 0.00
[2,] 0.001 0.500 0.000 0.0 0.00 0.00 0.00 0.00
[3,] 0.001 0.001 0.500 0.0 0.00 0.00 0.00 0.00
[4,] 0.001 0.001 0.001 0.5 0.00 0.00 0.00 0.00
[5,] 0.000 0.000 0.000 0.0 0.01 0.00 0.00 0.00
[6,] 0.000 0.000 0.000 0.0 0.00 0.01 0.00 0.00
[7,] 0.000 0.000 0.000 0.0 0.00 0.00 0.01 0.00
[8,] 0.000 0.000 0.000 0.0 0.00 0.00 0.00 0.01
$sigma
$sigma$matrices
$sigma$matrices[[1]]
[,1]
[1,] 1
$sigma$fixed
$sigma$fixed[[1]]
[1] TRUE |
- includes a refactored get_param_inits(), which now utilizes new WIP `nmrec` `get_{theta,omega,sigma}` functions. - Prototype supports all of the cases we have mentioned so far. Have manually tested other cases brought up in passing. - Code could be improved a bit to be more readable; perhaps a few helper functions could be used. - docs and tests are currently lacking
Some examples with the most recent refactor:.mod <- read_model(file.path(MODEL_DIR_C, "example2_saemimp")) Getting initial estimatesInternal function examplesBase case> get_initial_est(.mod)
$thetas
# A tibble: 13 × 3
init low up
<dbl> <dbl> <dbl>
1 NA 0 1
2 0.7 NA NA
3 0.7 0.67 0.72
4 2 NA NA
5 2 NA NA
6 0.7 NA NA
7 0.7 NA NA
8 2 NA NA
9 2 NA NA
10 0.7 NA NA
11 0.7 NA NA
12 0.3 NA NA
13 4 NA NA
$omegas
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.500 NA NA NA NA NA NA NA
[2,] 0.001 0.500 NA NA NA NA NA NA
[3,] 0.001 0.001 0.500 NA NA NA NA NA
[4,] 0.001 0.001 0.001 0.5 NA NA NA NA
[5,] NA NA NA NA 0.01 NA NA NA
[6,] NA NA NA NA 0.00 0.01 NA NA
[7,] NA NA NA NA 0.00 0.00 0.01 NA
[8,] NA NA NA NA 0.00 0.00 0.00 0.01
$sigmas
[,1]
[1,] 1 Flag fixed parameters> get_initial_est(.mod, flag_fixed = TRUE)
$thetas
# A tibble: 13 × 4
init low up fixed
<dbl> <dbl> <dbl> <lgl>
1 NA 0 1 FALSE
2 0.7 NA NA TRUE
3 0.7 0.67 0.72 FALSE
4 2 NA NA FALSE
5 2 NA NA FALSE
6 0.7 NA NA FALSE
7 0.7 NA NA FALSE
8 2 NA NA FALSE
9 2 NA NA FALSE
10 0.7 NA NA FALSE
11 0.7 NA NA FALSE
12 0.3 NA NA FALSE
13 4 NA NA TRUE
$omegas
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.500 NA NA NA NA NA NA NA
[2,] 0.001 0.500 NA NA NA NA NA NA
[3,] 0.001 0.001 0.500 NA NA NA NA NA
[4,] 0.001 0.001 0.001 0.5 NA NA NA NA
[5,] NA NA NA NA 0.01 NA NA NA
[6,] NA NA NA NA 0.00 0.01 NA NA
[7,] NA NA NA NA 0.00 0.00 0.01 NA
[8,] NA NA NA NA 0.00 0.00 0.00 0.01
attr(,"nmrec_flags")
attr(,"nmrec_flags")$fixed
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] FALSE NA NA NA NA NA NA NA
[2,] FALSE FALSE NA NA NA NA NA NA
[3,] FALSE FALSE FALSE NA NA NA NA NA
[4,] FALSE FALSE FALSE FALSE NA NA NA NA
[5,] NA NA NA NA TRUE NA NA NA
[6,] NA NA NA NA TRUE TRUE NA NA
[7,] NA NA NA NA TRUE TRUE TRUE NA
[8,] NA NA NA NA TRUE TRUE TRUE TRUE
$sigmas
[,1]
[1,] 1
attr(,"nmrec_flags")
attr(,"nmrec_flags")$fixed
[,1]
[1,] TRUE Exported function:
|
- add tests for getting initial estimates - update some docs
- need to put more thought into settting up template models. Couldnt use the approach I initially had in mind
- did a lot of testing with setting seeds both within the function (mostly via `withr`), and set outside. I think it's pretty robust now, but would like a second pair of eyes to ensure nothing else should be done - Pulled out random sampling into a separate helper function. Originally with the intention of inheriting the seed of the parent environment, though this did not work as desired. Decided to leave it as a separate function for now for code readability, and in the event we pass a `seed` argument within these functions
Hey @seth127, I just marked you for an intermediate review. Some things that still need to be done or talked about: Updates
Discussions
Im going to spend a little more time on documentation, but after that I was planning on waiting for a first review/some other parts to move along |
R/tweak-initial-estimates.R
Outdated
#' @details | ||
#' | ||
#' In the following cases, the initial estimate will *not* be updated: | ||
#' - **Individual** `FIXED` `THETA` parameters | ||
#' - e.g., `$THETA 1.2 FIX 1.5 0.2` --> would only skip the first value | ||
#' - **Individual** `FIXED` `OMEGA` & `SIGMA` parameters for *diagonal* matrices | ||
#' - e.g., `$OMEGA 0 FIX 1` --> would only skip the first value | ||
#' - **Full** `FIXED` `OMEGA` & `SIGMA` *block* matrices | ||
#' - e.g., `$OMEGA BLOCK(2) 0.1 0.001 0.1 FIX` --> would skip the full `OMEGA` record | ||
#' - `THETA` parameters with no initial estimate | ||
#' - e.g., `$THETA (0,,1)` | ||
#' | ||
#' For bounded `THETA` estimates: | ||
#' - If an initial `THETA` has bounds **and** an initial estimate | ||
#' (e.g., `(0, 0.5, 1)`, `(0,1)`), the bounds will be respected when sampling | ||
#' a percent to tweak by. If the tweaked value would fall below the lower bound, | ||
#' the initial estimate will be set to the lower bound. The same is true for | ||
#' upper bounds. | ||
#' - e.g., `(0, 0.5, 1)` --> tweak initially, falls outside bound (`(0, 1.2, 1)`) | ||
#' --> set to upper bound (`(0, 1, 1)`) | ||
#' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kyleam when you have a minute, im curious if you have any pointers/opinions on these docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you asked Kyle, but these make sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good, just few minor comments from this review.
I also want to note that we still have two outstanding questions about the omega (and also sigma?) matrices:
- Do we tweak the off-diagonals (if they're defined in the control stream) or not?
- How should we handle checking for (and possibly forcing) positive definiteness?
Either way, as discussed with @barrettk offline, our current plan for that is:
- Continue with this PR and merge it to
main
once review comments are addressed and the relevantnmrec
changes have landed (add functions for getting inits nmrec#30) - @barrettk to create a new issue to specifically address the outstanding matrix questions mentioned above.
- Address that new issue in a separate PR.
- Plan to not make a
bbr
release until all of that ^ has landed onmain
.
R/tweak-initial-estimates.R
Outdated
#' @details | ||
#' | ||
#' In the following cases, the initial estimate will *not* be updated: | ||
#' - **Individual** `FIXED` `THETA` parameters | ||
#' - e.g., `$THETA 1.2 FIX 1.5 0.2` --> would only skip the first value | ||
#' - **Individual** `FIXED` `OMEGA` & `SIGMA` parameters for *diagonal* matrices | ||
#' - e.g., `$OMEGA 0 FIX 1` --> would only skip the first value | ||
#' - **Full** `FIXED` `OMEGA` & `SIGMA` *block* matrices | ||
#' - e.g., `$OMEGA BLOCK(2) 0.1 0.001 0.1 FIX` --> would skip the full `OMEGA` record | ||
#' - `THETA` parameters with no initial estimate | ||
#' - e.g., `$THETA (0,,1)` | ||
#' | ||
#' For bounded `THETA` estimates: | ||
#' - If an initial `THETA` has bounds **and** an initial estimate | ||
#' (e.g., `(0, 0.5, 1)`, `(0,1)`), the bounds will be respected when sampling | ||
#' a percent to tweak by. If the tweaked value would fall below the lower bound, | ||
#' the initial estimate will be set to the lower bound. The same is true for | ||
#' upper bounds. | ||
#' - e.g., `(0, 0.5, 1)` --> tweak initially, falls outside bound (`(0, 1.2, 1)`) | ||
#' --> set to upper bound (`(0, 1, 1)`) | ||
#' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you asked Kyle, but these make sense to me.
- use dev tag and update drone
As @seth127 noted, we will need a separate PR to address these issues. The new
|
- fix test in R 4.0
@seth127 something I just thought about. This is related to a conversation @kyleam and I had regarding the handling of prior blocks that follow the old naming convention (see final thoughts). Basically, prior blocks currently get "grouped" when creating the combined matrix. This would also occur for THETA records: Example> MODEL_DIR_X
[1] "inst/model/nonmem/complex"
> .mod <- read_model(file.path(MODEL_DIR_X, "example2_saemimp")) ctl <- nmrec::read_ctl(get_model_path(.mod))
> nmrec::extract_omega(ctl)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.500 NA NA NA NA NA NA NA
[2,] 0.001 0.500 NA NA NA NA NA NA
[3,] 0.001 0.001 0.500 NA NA NA NA NA
[4,] 0.001 0.001 0.001 0.5 NA NA NA NA
[5,] NA NA NA NA 0.01 NA NA NA
[6,] NA NA NA NA 0.00 0.01 NA NA
[7,] NA NA NA NA 0.00 0.00 0.01 NA
[8,] NA NA NA NA 0.00 0.00 0.00 0.01 In the
I was reminded about this conversation when doing some preliminary testing for the positive-definiteness, but now im not sure if we should address this in this PR, given that it also implicates Im not really sure how to handle this. In the case of |
My opinion for how to proceed is what I said in the issue you linked: we should document that using non-informative record names for priors is not supported with this feature. |
@kyleam said
and I think I agree with that, in principle. However, in practice, we never know that they're using non-informative priors in this case. Above, @barrettk said
I've looked through the code a bit and I'm pretty sure that's right. My evidence:
I also tried this empirically and saw the same thing:I tried with .mod <- read_model(file.path(MODEL_DIR_X, "example2_saemimp"))
tweak_initial_estimates(.mod) results in this Soooooo... that means we can't just leave it as is and expect that error to bubble up. |
In effect, this means that the current state actually tweaks non-informative priors too. The big question from me: is it ok for us to tweak the non-informative priors the same way that we tweak the initial parameter estimates? If so, then we can just document that behavior and move on. If that's not ok... then I'm not sure what the next step is. I guess I'd just say "let's cross that bridge when we come to it" (and hope we don't come to it). @curtisKJ @timwaterhouse could either of you weigh in on my "big question" at the top of this comment? One final note (in favor of leaving as is): anecdotally, in most cases I've seen, the non-informative priors use |
Thanks @seth127. I haven't reviewed this PR or been involved in many of the design discussions, so it's helpful to see you expand on those details.
In the linked thread, I had assumed that would trigger, but for the latest comment here I took for granted @barrettk's claim that that doesn't get triggered. (Thank you both for pointing that out.) So, in the comment above, I was just casting my vote for documenting that this feature is not meant to be used with uninformative prior names, accepting that it will jitter them if there (i.e. your "document that behavior and move on"). A few more thoughts:
|
Thanks @kyleam I appreciate those thoughts. You said
I actually had this same thought this morning. That's reassuring, and I think will likely cover a lot of cases. To be clear (for anyone else reading this), we're talking about a pattern like this, which several people have mentioned wanting to be able to do: mod2 <- mod1 %>%
copy_model_from() %>%
inherit_param_estimates() %>%
tweak_initial_estimates() In that case, if We're going to discuss with a few scientific folks offline. Unless they object, I'm leaning towards this
|
I had said
Unfortunately, @timwaterhouse and @curtisKJ do object. Essentially, they said we definitely don't want to tweak the priors. Two things we're going to look into:
@barrettk I believe you're taking this ^ on, right? |
The proposal isn't that anyone wants to tweak them. It's just accepting that the caller can violate the documented use in a way that leads to them being tweaked. Was the conclusion "we're going to insist that the outcome is severe enough that we really want to prevent that mistake"?
Perhaps it's worth considering rethinking the design to always use an executed model as the starting point (my "reworking things so that jittering is coupled to estimates from a previous model" bullet point above). That'd give you a reliable answer to what the shape should be. |
Just a few comments, in case it's helpful...
At least based on the nwpri docs, it looks like that could be the case. I see a lot of "values on these records must be fixed", but perhaps a closer look would show cases where that's not said or perhaps there are other more relevant docs.
My conclusion that the prior block isn't sufficient is based on the nwpri docs saying "a $PRIOR record may be used instead of a user-written PRIOR subroutine, in which case the input arguments listed above may be specified as options of $PRIOR". |
In response to @seth127's comment:
Seth and I talked offline about this. It is still something worth looking into, but we decided it isnt really a complete solution, as we want to be able to identify prior records in order to remove them from In response to @kyleam's comments:
The conclusion is that we needed to guarantee priors wouldnt be altered, even using the old method. It's apparently a large deal so we need some method of determining if priors are being used at the minimum. Identifying the specific records that are priors is ideal, but we need to at least know if they're being used.
The jittering feature has to be separate from the
|
It seems to me that that line of thinking is in direct contradiction to claiming you must "guarantee priors wouldnt be altered".
I understand that (I think, at least). My suggestion is that you reconsider that design decision due to the desire to reliably know if there is a shape mismatch due to prior use. If we decide not to go that direction, that's of course fine, but here it feels like you're just dismissing the suggestion by reasserting what's already a given. |
Perhaps I didnt provide enough detail here. We need to know if there are priors with certainty (so worst case we could error out and not support it). The line you referenced would be the ideal state, and would handle almost all cases of being able to filter out priors. It's fine if we cant guarantee the identification of specific prior records.
It's more that this is not the direction we want to go first. That is something we would consider if parsing priors seems too finicky/unreliable, but we want to attempt that direction first. We could only go that direction if we required a previously executed model run to pull out previous estimates, and there is at least a notable preference to not do that based on my discussions with Seth, Curtis and Tim (easier to have these discussions over zoom). That's something I can discuss with @seth127 next week when he gets back, but for now I have directions to look into the parsing of prior records. |
Proposed path forward on priorsI talked with @barrettk for bit yesterday and I have a proposed path forward that I'd love some feedback on. I'll say upfront that my main motivation here is not wanting to try to identify and filter out the non-informative priors. Given discussion above, and some further research, this seems like a huge pain. I also don't like the idea of making this feature rely on a previously run model. (I'm happy to go into detail on either of those points, if anyone is interested.) So then, my proposal:
Thoughts on that? Anything that I'm missing? DetailsHere is some pseudo-code I threw together with the heuristic I have in mind: bbr:::using_old_priors#' This function uses a simple heuristic to decide
#' whether the control stream appears to be using the old
#' "non-informative" method of specifying priors
bbr:::using_old_priors(.ctl) {
# check if PRIORS are being used
prior_recs <- nmrec::select_records(.ctl, "prior")
prior_subs <- nmrec::select_records(.ctl, "sub")
prior_subs <- any(stringr::str_detect(prior_subs, "PRIOR")) # probably want nmrec to parse to see if PRIOR shows up in here...
# check if INFORMATIVE style is present
informative_priors <- purrr::walk(
c("thetap", "thetapv", "omegap", "omegapd", "sigmap", "sigmapd"), # ARE THERE OTHERS???
~ {nmrec::select_records(.ctl, .x)}
)
# if priors are specified AND _not_ using informative style, then assume using old style
if (
((length(prior_recs) || length(prior_subs)) > 0) &&
length(informative_priors) == 0
) {
return(TRUE)
}
return(FALSE)
} Then we call that in if (isTRUE(using_old_priors(ctl))) {
rlang::warn(paste(
"This model appears to be using the old 'non-informative' method of specifying priors.",
"That will cause this function to extract and display priors as if they are initial parameter estimates.",
"Consider changing the model to use informative prior record names (such as THETAP and THETAPV)."
))
} and then we go on with our day... |
Still working on some matrix stuff before I commit the latest changes, but here are some examples of getting the initial estimates, based on some of the above discussion (including @seth127's most recent comment): Example with no priors (`MOD1`)> initial_estimates(.mod)
# A tibble: 8 × 6
parameter_names record_type init lower_bound upper_bound record_number
<chr> <chr> <dbl> <dbl> <dbl> <int>
1 THETA(1) theta 2 0 NA 1
2 THETA(2) theta 3 0 NA 1
3 THETA(3) theta 10 0 NA 1
4 THETA(4) theta 0.02 NA NA 1
5 THETA(5) theta 1 NA NA 1
6 OMEGA(1,1) omega 0.05 NA NA 1
7 OMEGA(2,2) omega 0.2 NA NA 1
8 SIGMA(1,1) sigma 1 NA NA 1 Example when using informative priors> initial_estimates(.mod)
# A tibble: 15 × 6
parameter_names record_type init lower_bound upper_bound record_number
<chr> <chr> <dbl> <dbl> <dbl> <int>
1 THETA(1) theta -0.574 NA NA 1
2 THETA(2) theta 5.67 NA NA 1
3 THETA(3) theta 1.04 NA NA 1
4 THETA(4) theta 0.242 NA NA 1
5 THETA(5) theta -11.4 NA NA 1
6 THETA(6) theta 5.11 NA NA 1
7 OMEGA(1,1) omega 0.09 NA NA 1
8 OMEGA(2,2) omega 0.09 NA NA 2
9 OMEGA(3,2) omega 0.01 NA NA 2
10 OMEGA(4,2) omega 0.01 NA NA 2
11 OMEGA(3,3) omega 0.09 NA NA 2
12 OMEGA(4,3) omega 0.01 NA NA 2
13 OMEGA(4,4) omega 0.09 NA NA 2
14 SIGMA(1,1) sigma 0.04 NA NA 1
15 SIGMA(2,2) sigma 0.04 NA NA 1 Example when ***not*** using informative priors> initial_estimates(.mod)
# A tibble: 33 × 6
parameter_names record_type init lower_bound upper_bound record_number
<chr> <chr> <dbl> <dbl> <dbl> <int>
1 THETA(1) theta 0.7 NA NA 1
2 THETA(2) theta 0.7 NA NA 1
3 THETA(3) theta 2 NA NA 1
4 THETA(4) theta 2 NA NA 1
5 THETA(5) theta 0.7 NA NA 1
6 THETA(6) theta 0.7 NA NA 1
7 THETA(7) theta 2 NA NA 1
8 THETA(8) theta 2 NA NA 1
9 THETA(9) theta 0.7 NA NA 1
10 THETA(10) theta 0.7 NA NA 1
# ℹ 23 more rows
# ℹ Use `print(n = ...)` to see more rows
Warning message:
! This model appears to be using the old 'non-informative' method of specifying priors.
ℹ - That will cause this function to extract and display priors *as if* they are initial parameter estimates.
ℹ - Consider changing the model to use informative prior record names (such as THETAP and THETAPV). Function for checking for non-informative priors:cc @kyleam to check out this modified function as well as Seth's comment above Function#' Check if PRIORS are being used
using_old_priors <- function(ctl) {
# pull prior related records
prior_recs <- nmrec::select_records(ctl, "prior")
subroutine_recs <- nmrec::select_records(ctl, "sub")
if(length(subroutine_recs) > 0){
prior_subs <- purrr::map_lgl(subroutine_recs, function(prior_sub){
prior_sub_str <- prior_sub$get_lines()
# filter out comments
prior_sub_str <- gsub(";.*", "", prior_sub_str)
# look for priors
any(stringr::str_detect(prior_sub_str, "(?i)PRIOR"))
})
prior_subs <- any(prior_subs)
}else{
prior_subs <- FALSE
}
# check if INFORMATIVE style is present
prior_names <- c("thetap", "thetapv", "omegap", "omegapd", "sigmap", "sigmapd")
informative_priors <- purrr::map(prior_names, function(.x){
recs <- nmrec::select_records(ctl, .x)
if(length(recs) == 0) return(NULL) else return(recs)
}) %>% purrr::list_c()
# if priors are specified AND _not_ using informative style, then assume using old style
if ((length(prior_recs) > 0 || isTRUE(prior_subs)) && length(informative_priors) == 0){
return(TRUE)
}
return(FALSE)
} |
Sounds like a reasonable path forward to me. |
- `initial_estimates()` now tabuluates the record number - We check if non-informative priors are being used - tweaking each parameter type is now pulled out into separate helper functions. The `tweak_matrix` function will be altered in a later PR to address positive-definiteness
@seth127 Your proposal looks reasonable to me as well. My only suggestion would be to change the language for "informative" and "non-informative" record names, since that has specific meaning for Bayesian priors. I know the NONMEM documentation calls them that, but I think something like this might be more clear: if (isTRUE(using_old_priors(ctl))) {
rlang::warn(paste(
"This model appears to be using $THETA, $OMEGA, and/or $SIGMA to specify priors.",
"That will cause this function to extract and display priors as if they are initial parameter estimates.",
"Consider changing the model to use the more specific prior record names (such as $THETAP and $THETAPV)."
))
} |
@timwaterhouse The only issue with changing the naming convention, is that |
I agree with the suggestion to avoid "non-informative" and will update nmrec. |
The set-param and extract-param docs call records like THETAP and THETAPV as "informative prior record names" because NONMEM refers to records like THETAP and THETAPV as "informative record names". However, that invites confusion with the unrelated statistical concept of informative/non-informative priors (even more so because the nmrec docs unnecessarily insert "prior" between "informative" and "record names"). Drop "informative" entirely to avoid confusion. While at it, reduce "prior record names" to "record names" because "prior" makes it harder to parse and is unnecessary given the context. Thanks to @timwaterhouse for the suggestion. Re: metrumresearchgroup/bbr#635 (comment)
Getting initial parameter estimates
The goal was to return an object that looked similar to
param_estimates()
. The internal functionget_initial_est()
, returns all values (i.e. the full diagonally concatenatedOMEGA
matrix if multiple records are provided) in a list format, whereas the wrapperinitial_estimates()
, only displays values defined in the control stream file`initial_estimates()` example
If you would like to format OMEGA or SIGMA records as full matrices, they are stored as attributes:
Tweaking initial estimates
The details below are also found in the function docs:
Usage
Walkthrough
Starting Record
Tweak values
After Tweaking
closes #632