Giter Club home page Giter Club logo

mmrm's People

Contributors

arkadiuszbeer avatar brianlang avatar chstock avatar cicdguy avatar clarkliming avatar danielinteractive avatar danjamstat avatar danleibovitz avatar ddsjoberg avatar dgkf avatar eldeveloper avatar gowerc avatar juliadedic1 avatar kkmann avatar melkiades avatar ndunnewind avatar philboileau avatar shajoezhu avatar szcf-weiya avatar walkowif avatar yonicd avatar ywang-gilead avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mmrm's Issues

Add function `h_record_all_output()`

To do:

  • See design document here
  • Add Craig and Alessandro as authors in the DESCRIPTION file (see https://github.com/insightsengineering/rbmi for emails etc)
  • Add function h_record_all_output() in file R/output.R
  • Add unit tests in file testthat/test-output.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Add function `h_cov_estimate()`

To do:

  • See design document here
  • Add function h_cov_estimate() in file R/covariance.R
  • Add unit tests in file testthat/test-covariance.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

few things around `component()`

To do:

  • remove AIC, BIC, deviance, logLik since we have direct accessors already
  • remove method
    • don't print it in print method
    • I guess otherwise not needed
  • Add @details section with md list explaining the possible return values

Design the flow for fitting MMRM

To do:

  • check_vars [old]
  • build_formula [old]
    • see also rbmi
    • needs different result now that we are using glmmTMB
  • get_cov_estimate [old]
    • this should be much simpler now with glmmTMB, no manual construction should be necessary
  • get_diagnostics [old]
    • change assertions
    • might need to change code slightly
  • fit_single_optimizer [old]
    • see rbmi
    • this needs quite some work
  • summarize_all_fits [old]
    • needs changes due to glmmTMB
  • get_free_cores [old]
    • probably can be used more or less identically as old code
  • refit_multi_optimizers [old]
    • see also rbmi but note that logic is slightly different
      • we still want parallelization
      • and we want to select among converged fits the one with best criterion - use summarize_all_fits to do that
  • fit_model [old]
    • this is wrapping the lower level functions fit_single_optimizer and refit_multi_optimizers
  • mmrm [old]
    • does everything together and returns mmrm object
  • lsmeans computations [old]
    • save main results for Satterthwaite calculation within the mmrm model fit object
    • define a df_1d() function/method calculating ST df for 1d case
    • define a df_md() function/method for multidimensional (F) case
    • define extensions to emmeans generic functions recover_data and emm_basis, very similar as defined for glmmTMB in emmeans.R
      • emm_basis then uses df_md()
    • afterwards, emmeans should work for mmrm model objects

Add `print` method for `mmrm_tmb`

This is nice for handling the results and will make testing of the package easier.

To do:

  • see how other packages are doing it, e.g.:
    • glmmTMB: glmmTMB uses print.glmmTMB to present their objects, with the typical model output that one would expect. Very similar to what is spec'd below.
    • lme4: for lmList4 they use show to print out a model summary (coded within the function body), for merMod they first spec a S3 print method, and then call that in the S4 show method body. The difference seems to be that lmList4 inherits the print method from lme objects from the nmle package.
  • do a nice first version (does not need to be perfect)

Add `summary()` method

This is important since we get the fixed effect estimates table from that.

To do:

  • check how other packages are implementing this (e.g. class that has a show method etc.)
    • glmmTMB:::summary.glmmTMB produces such object
    • glmmTMB:::print.summary.glmmTMB prints it
  • summary:
    • add vcov() method
    • add VarCorr() method
    • add coef() method
    • h_coef_table() helper
    • make sure to include Satterthwaite d.f.
  • print:
    • no need for residuals right now
    • h_print_call() a la glmmTMB:::.prt.call.glmmTMB
    • h_print_aic_list() a la lme4:::.prt.aictab

Add homogeneous Toeplitz covariance structure

To do:

  • Add definition of homogeneous Toeplitz covariance structure to covariance vignette
    • merge it together with heterogeneous Toeplitz covariance we already have
    • rename heterogeneous to toeph and keep the homogeneous as toep- carry this through below
  • Adjust covariance structure choices in

    mmrm/R/tmb.R

    Line 60 in 709f392

    corr_functions <- c("us", "toep", "ar1", "cs", "ad")
  • Initialize start parameters in

    mmrm/R/tmb.R

    Line 208 in 709f392

    theta_dim <- as.integer(switch(formula_parts$corr_type,
  • Amend printing of covariance structure in
    cov_definition <- switch(cov_type,
  • Add lower Cholesky factor function and include it in branching in
  • Amend integration tests in
    # h_mmrm_tmb ----
    • Note that r2stream is not available outside of Roche, so just run SAS differently and save log as text file in the design folder as reference
  • Run Clean and Rebuild > Check to ensure that checks pass
    • One test failed @danielinteractive can we consider this one as pass?
      image
    • Chang the tolerance to 1e-3 for this test

Robust sandwich estimator

To do:

  • Understand and describe what combinations of ST and KR work or don't work from methods point of view with sandwich estimator
  • Check how package clubSandwich does it
    • Especially for gls result objects (since our model is also a general least squares model)
  • Derive formulas for our case -> write design doc
  • Implement prototype calculations
  • Compare for one or two examples with SAS results
  • extend with method here in mmrm package
    • add news
    • add vignettes
    • add both jackknife and empirical
    • a simple "residual" degree of freedom is added; n_obs - n_params to make things run;
    • add unit tests
    • add integration tests
      • compared empirical with SAS result
      • compared Jackknife with nlme::gls + clubSandwich::vcovCR(type = "CR3")
      • compared weighted empirical with SAS
      • compared weighted Jackknife with nlme::gls + clubSandwich::vcovCR(Please note that the weight used in gls is the inverse of the weight used in SAS and mmrm)

Just fyi: Here is some simple example of gls() with clubSandwich - might be nice to play around with

library(nlme)
m <- gls(
  value ~ time*method,
  correlation =corCompSymm(form=~1|patient_id), 
  data = x, 
  na.action = na.omit, 
  method = "REML"
)
 
emmeans::emmeans(
  m, 
  specs = ~time*method,
  vcov = matrix(clubSandwich::vcovCR(m, type = "CR3"), nrow=6)
)

Add possibility to set `weights` to obtain weighted MMRM

To do:

  • Amend algorithm vignette to understand how the weights would be included in the fitting process
  • Add argument to mmrm() and related functions (to be detailed here)
    • Add argument to mmrm() and fit_single_optimizer() in file R/fit.R
    • Add argument to h_mmrm_tmb and h_mmrm_tmb_data in file R/tmb.R
    • Update file /src/mmrm.cpp
  • For lower level functions: Add unit tests for the weights functionality for all functions which are involved
  • For mmrm(): Add integration test where we compare results with SAS results
    • seems ok for weights = 1 (no weights)
    • resolve differences for random weights
    • including d.f.
  • For print() method: It would be good if we could include a line that mentions the weights there
  • Document in the introduction vignette

Find reference for corrected AIC formula

Add function `h_build_formula()`

To do:

  • See design document here
  • Add function h_build_formula() in file R/formula.R
  • Add unit tests in file testthat/test-formula.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Add `h_free_cores()` function

To do:

  • See design document here
  • Add function h_free_cores() in file R/parallel.R
  • Add simple unit test in file testthat/test-parallel.R
    • In this case e.g. just have one test that checks if the function runs silently without messages e.g.
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Design for Type II and Type III tests a la `car::Anova()`

To do:

Note (from ?car::Anova? Details):
The designations "type-II" and "type-III" are borrowed from SAS, but the definitions used here do not correspond precisely to those employed by SAS.

  • Type-II tests are calculated according to the principle of marginality, testing each term after all others, except ignoring the term's higher-order relatives; This definition of Type-II tests corresponds to the tests produced by SAS for analysis-of-variance models, where all of the predictors are factors, but not more generally (i.e., when there are quantitative predictors).
  • so-called type-III tests violate marginality, testing each term in the model after all of the others. Be very careful in formulating the model for type-III tests, or the hypotheses tested will not make sense.

Add `refit_multiple_optimizers()`

depends on #25

To do:

  • See design document here
  • Add method formula() for mmrm_tmb
    • add unit test
  • Add function refit_multiple_optimizers() in file R/fit.R
    • align optimizers with the ones from single optimizer fit function
  • Add unit tests in file testthat/test-fit.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Add function `mmrm_tmb()` that fits an MMRM with `TMB`

Idea: Add a function that replaces glmmTMB::glmmTMB() call in

mmrm/R/fit.R

Line 37 in b0a1ff3

glmmTMB::glmmTMB(
.
(This can potentially also replace fit_single_optimizer, let's see)

To do:

Add antedependence correlation

To do:

Avoid or improve `enum` mapping

Motivation: Currently we are mapping the covariance structures to their C++ enum integer codes here

mmrm/R/tmb.R

Line 169 in b1b6122

cov_type <- as.integer(switch(formula_parts$cov_type,

Ideal outcome: Can we avoid this completely and just pass the cov_type string (e.g. ar1) directly to C++ and then decide based on that?

Otherwise: Somehow do the enum conversion in a more robust way.

Check `NEWS` entry etc. for internal pre-release

Please re-read the NEWS.md file and make it human readable, i.e. re-organise, change order, combine entries, group them if applicable, full sentence, no new entries on the old version (!) etc.

Replace copyright holder

Use F. Hoffmann-La Roche Ltd., 2022 instead of openpharma. Can discuss again when somebody else is contributing code.

Add Heterogeneous 1st order autoregressive correlation

To do:

Comparison with other implementations / packages

For marketing/usability, we should provide users with a description as to how/why mmrm would be more appropriate than the other available packages.

In particular: lme4, nlme, and glmmTMB.

This documentation could fit well in a separate vignette "Comparison with other packages", so that potential users can immediately understand where/when we think our development can help them compared to packages with higher levels of adoption.

Design for Kenward-Roger d.f.

Material:

Add more functions towards Satterthwaite and LS means functionality

To do:

  • See https://github.com/openpharma/mmrm/blob/main/design/design_fit.Rmd
  • h_covbeta_fun() (this should be much simpler now)
  • h_jac_col_as_matrix() (factored out helper)
  • h_jac_list()
  • modify fit_model() a la mmrm() and rename it to mmrm()
    • add the Jacobian calculation on top
    • add mmrm class to existing classes for return object, such that we know that we have the Jacobian in there
    • rename mmrm_tmb() to h_mmrm_tmb() to avoid confusion
  • diagnostics:
    • deviance()
    • AIC()
    • BIC()
  • h_quad_form_vec()
  • h_gradient()
  • h_df_1d_list()
  • df_1d()
  • h_quad_form_mat()
  • h_df_md_list()
  • h_md_denom_df()
  • df_md()
  • recover_data.mmrm() needs
    • call saved
    • terms() method
  • emm_basis.mmrm() - also here more needs to be done

Note that we don't need:

  • h_general_jac_list() (since no other jacobian calculations besides from our TMB fit)
  • vars() (since we can stick with the formula interface for this package)
  • h_vcov_theta() (since we have that explicitly as part of the object already)
  • separate mmrm() as another wrapper of fit_model() (since we don't need vars interface and we can just calculate Jacobian in fit_model() directly)
  • diagnostics() (this is more a wrapper for tern.mmrm)

Add homogeneous ante-dependence covariance structure

To do:

  • Add definition of homogeneous ante-dependence covariance structure to covariance vignette
    • merge it together with heterogeneous ante-dependence covariance we already have
    • rename heterogeneous to adh and keep the homogeneous as ad- carry this through below
  • Adjust covariance structure choices in

    mmrm/R/tmb.R

    Line 60 in 709f392

    corr_functions <- c("us", "toep", "ar1", "cs", "ad")
  • Initialize start parameters in

    mmrm/R/tmb.R

    Line 208 in 709f392

    theta_dim <- as.integer(switch(formula_parts$corr_type,
  • Amend printing of covariance structure in
    cov_definition <- switch(cov_type,
  • Add lower Cholesky factor function and include it in branching in
  • Amend integration tests in
    # h_mmrm_tmb ----
    • Note that r2stream is not available outside of Roche, so just run SAS differently and save log as text file in the design folder as reference --> change to use mmrm results for testing since homegeneous ad cov is not available in SAS
  • Run Clean and Rebuild > Check to ensure that checks pass

Add introduction to introduction vignette

To do:

  • Add the main part "introduction" to the introduction vignette
  • To cover:
    • simple model fit (similar like in README)
    • changing to REML, changing optimizer, changing covariance structure
    • extracting coefficients table from summary result, refer to mmrm_tmb_methods for others
    • explain lower level function h_mmrm_tmb() - mainly useful if you don't need Satterthwaite d.f. or try other optimizers, "barebones" function
    • Show how to use emmeans package, refer to emmeans_support

Support models where original design matrix is not full rank

Background:
It can happen that the design matrix that is created from the model formula does not have full rank. This can be due to some visit and arm combinations not being present in the data set, or too many (categorical) covariates that lead to exact collinearities between columns.

Reprex:

dat <- fev_data[11:25, ]
fit <- h_mmrm_tmb(
  formula = FEV1 ~ RACE + SEX + ARMCD * AVISIT + us(AVISIT | USUBJID),
  data = dat
)

gives error

Error in h_mmrm_tmb_assert_start(tmb_object) : 
negative log-likelihood is NaN at starting parameter values

Comparing this with the lm result:

linmod <- lm(
  formula = FEV1 ~ RACE + SEX + ARMCD * AVISIT,
  data = dat
)
summary(linmod)

we can see that the coefficients for ARMCDTRT:AVISITVIS2 and ARMCDTRT:AVISITVIS3 are not defined due to singularities. We also note that lm() has the corresponding argument singular.ok = TRUE controlling whether this works or gives an error.

To do:

  • Understand how lm() is organizing this
    • in lm.fit(), compiled code is called (see http://madrury.github.io/jekyll/update/statistics/2016/07/20/lm-in-R.html for a summary) which is implicitly handling the singular design matrix.
    • the R code then sorts in the NAs of the non-identified columns correctly
    • downstream the coef() and vcov() methods have complete = TRUE argument which controls if the NA coefficients should be represented
    • note that the summary() method finally computes the variance covariance matrix only for the identified coefficients, based on the QR decomposition. the resulting coefficient table has all NA for the non-identified coefficients. when printed it also says (2 not defined because of singularities) e.g.
  • Here it seems to be easier to already sort out the non-identifiable columns before going into C++
    • should be handled by h_mmrm_tmb_data()
      • Add argument accept_singular = TRUE
      • the x_matrix should already be the reduced one - need to be careful how the attributes map formula contents to columns
      • full_frame should contain still the full data frame
      • additional x_cols_aliased element to say which coefficients have been removed already
    • Add argument accept_singular = TRUE to h_mmrm_tmb_control()
  • check that up/downstream this works as expected or adapt accordingly
    • mmrm
    • component
    • print
    • coef
    • vcov
    • df_1d, df_md: these only refer to the actually estimated coefficients and their covariance matrix
    • h_coef_table
    • summary
    • emmeans
  • check how tern.mmrm digests this and adapt if needed

Add `fit_model()`

To do:

  • See design document here
  • Add function fit_model() in file R/fit.R
  • Add unit tests in file testthat/test-fit.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Add `h_summarize_all_fits()`

To do:

  • See design document here
  • Add function h_summarize_all_fits() in file R/fit.R
    • Add unit tests in file testthat/test-fit.R
  • Add logLik method in file R/tmb-methods.R
    • Add corresponding unit test
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Add function `h_labels()` with helpers

To do:

  • See design document here
  • Add function h_labels() in file R/labels.R
  • Add unit tests in file testthat/test-labels.R
    • If needed please improve the function code
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass

Address warnings and notes (as much as possible) from `R CMD check`

On enableR:
The following notes and warnings are generated when R CMD check is run against this package.

* checking compilation flags used ... NOTE
Compilation used the following non-portable flag(s):
  โ€˜-Werror=format-securityโ€™ โ€˜-Wp,-D_FORTIFY_SOURCE=2โ€™
  โ€˜-Wp,-D_GLIBCXX_ASSERTIONSโ€™
* checking compiled code ... WARNING
File โ€˜mmrm/libs/mmrm.soโ€™:
  Found โ€˜abortโ€™, possibly from โ€˜abortโ€™ (C)
    Objects: โ€˜mmrm.oโ€™, โ€˜test-covariance.oโ€™, โ€˜test-runner.oโ€™,
      โ€˜test-utils.oโ€™, โ€˜tmb.oโ€™
  Found โ€˜printfโ€™, possibly from โ€˜printfโ€™ (C)
    Objects: โ€˜mmrm.oโ€™, โ€˜test-covariance.oโ€™, โ€˜test-runner.oโ€™,
      โ€˜test-utils.oโ€™, โ€˜tmb.oโ€™
File โ€˜mmrm/libs/mmrm.soโ€™:
  Found no calls to: โ€˜R_registerRoutinesโ€™, โ€˜R_useDynamicSymbolsโ€™

Compiled code should not call entry points which might terminate R nor
write to stdout/stderr instead of to the console, nor use Fortran I/O
nor system RNGs.
It is good practice to register native routines and to disable symbol
search.

See โ€˜Writing portable packagesโ€™ in the โ€˜Writing R Extensionsโ€™ manual.

To do:

  • be able to reproduce this - on enableR?...
  • fix it if possible
    • it is not clear where the non-portable flags come from. Possibly from TMB. However this warning does not show up without CRAN flag or on R 4.2 so should be ok.
    • it is not clear where the abort and printf symbols come from. I checked the C++ code and we don't have any of this or similar. Maximum we have is Rf_error which is standard R interface for an error so cannot be the problem. Note that this warning does not occur on R 4.2

On Daniel's Macbook with R CMD check --as-cran on the built package tarball:

* checking compiled code ... NOTE
Datei โ€˜mmrm/libs/mmrm.soโ€™:
  Found no calls to: โ€˜R_registerRoutinesโ€™, โ€˜R_useDynamicSymbolsโ€™

It is good practice to register native routines and to disable symbol
search.

See โ€˜Writing portable packagesโ€™ in the โ€˜Writing R Extensionsโ€™ manual.

To do:

Moreover parallel processes are not allowed in CRAN:

 โœ– | 2      47 | fit [0.7s]                                                      
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Error (test-fit.R:175:3): mmrm falls back to other optimizers if default does not work
  Error in `.check_ncores(cores)`: 3 simultaneous processes spawned
  Backtrace:
    1. testthat::expect_silent(mmrm(formula, data_small))
         at test-fit.R:175:2
    9. mmrm::mmrm(formula, data_small)
   10. mmrm::refit_multiple_optimizers(fit, n_cores = n_cores, accept_singular = accept_singular)
   13. parallel::mclapply(...)
   14. parallel:::.check_ncores(cores)
  
  Error (test-fit.R:185:3): mmrm fails if no optimizer works
  Error in `.check_ncores(cores)`: 3 simultaneous processes spawned
  Backtrace:
    1. testthat::expect_error(...)
         at test-fit.R:185:2
    7. mmrm::mmrm(formula, data_small, reml = FALSE)
    8. mmrm::refit_multiple_optimizers(fit, n_cores = n_cores, accept_singular = accept_singular)
   11. parallel::mclapply(...)
   12. parallel:::.check_ncores(cores)
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

To do:

  • disable parallel processing in the 2 tests

Add compound symmetry covariance structures

To do:

Add a first spatial covariance structure: spatial exponential

To do:

  • Read a bit about spatial covariance structures, e.g. at https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.3/statug/statug_mixed_syntax14.htm
  • Adapt algorithm vignette (write down theoretical part - e.g. in this case we don't start from a common covariance matrix for all patients but construct a new one for each patient based on the coordinates)
  • Adapt covariance structure vignette (write down theoretical part of the exponential cov structure)
  • Think about how to best receive the required numeric time point values from the user
    • Note that so far we are just taking the levels of the time point (factor) variable in their order
    • Note that also multiple numeric columns might represent together the coordinates of a single visit
  • Think about how to best pass on the numeric time coordinates to the C++ code
  • Add definition of spatial in general and spatial exponential covariance structure in particular to covariance vignette
  • Adjust covariance structure choices in

    mmrm/R/tmb.R

    Line 60 in 709f392

    corr_functions <- c("us", "toep", "ar1", "cs", "ad")
  • Initialize start parameters in

    mmrm/R/tmb.R

    Line 208 in 709f392

    theta_dim <- as.integer(switch(formula_parts$corr_type,
  • Amend printing of covariance structure in
    cov_definition <- switch(cov_type,
  • Add lower Cholesky factor function and include it in branching in
  • Amend integration tests in
    # h_mmrm_tmb ----
    • Note that r2stream is not available outside of Roche, so just run SAS differently and save log as text file in the design folder as reference
  • Run Clean and Rebuild > Check to ensure that checks pass

Add 1st order autoregressive correlation

To do:

Hex Sticker renders twice on index.html

The hex sticker renders twice on index.html.

This is because we need to add
<p align="center"> <img src="man/figures/logo.svg" align="right" alt="mmrm-logo" style="width: 150px"> </p>
into README.Rmd so that the .md file in GitHub will show the sticker.

Then, in the website, pkgdown builder adds a header with logo.svg for all of the pages rendered to HTML. In this way, index.html has two hex stickers.

Screenshot 2022-08-22 at 10 32 47

I thought that maybe we could follow some sort of approach with conditional code depending on output format, and we'd want the .md to render with the above code, and the .html to render without.

Since .Rd is the first step in the .Rmd -> .md -> html pipeline, the knitr::opts_knit are identical for both .md and .html output, se we couldn't use this to differentiate.

If we care about this appearance issue, we would probably need to remove the code from the .Rmd and inject it into the .md file. Doing this by hand would be quite unsustainable.

Add the functionality to have separate covariances matrices per group / treatment arm

Note: In that case we need covariance structure formula part like this:
us(visit | group / subjid)

To do:

  • Edit the algorithm vignette to understand how the group specific covariance matrices would be included
  • adapt formula parsing
    • group needs to be a factor, drop levels
  • adapt data passed to TMB
    • need to pass the group information
    • need to initialize a longer theta vector (e.g. store each covariance matrix in contiguous part)
  • in C++:
    • start by constructing Cholesky factor for each group
    • within the loop check which group a subject belongs to and take that factor
    • report list of factors
  • construct list of covariance matrix estimates instead of just one
  • rest should stay the same
  • add integration tests to compare with SAS results
  • explain in introduction vignette under "Common customizations"
  • include yourself in authors of the package :-)

Clean up exports

To do:

  • decide which objects do not need to be exported
  • add appropriate badge experimental, stable, deprecated to all exported objects
  • _pkgdown.yaml should only contain exported objects
  • unexported objects must have documentation but they need @keywords internal tag and must not have examples (since those won't run)
    • when removing examples from those, please make sure that the same thing is covered in existing unit tests, or otherwise add the example as a new unit test - so that we don't lose covering that case basically.
  • Use this script to easily detect what is left to do.
#' packages having keyword internal and matching specific type
rd_index_installed <- function(pkg, type = NULL) {
  db <- tools::Rd_db(pkg)
  elo <- tools:::.build_Rd_index(tools:::Rd_contents(db), type = type)
  elo$Name
}

man_files <- function(path) {
  list.files(file.path(path, "man"), full.names = TRUE, pattern = ".Rd")
}

rd_index <- function(path = ".") {
  all_docs <- man_files(path)
  res <- vapply(all_docs, FUN.VALUE = logical(1), FUN = function(x) {
    lines <- readLines(x)
    any(grepl("keyword\\{.*internal\\}", lines))
  })
 sort(gsub(".Rd$", "", basename(names(res[!res]))))
}

badge <- function(path = ".") {
  all_docs <- man_files(path)
  res <- vapply(all_docs, FUN.VALUE = logical(1), FUN = function(x) {
    lines <- readLines(x)
    any(grepl("figure\\{lifecycle", lines))
  })
  sort(gsub(".Rd$", "", basename(names(res[res]))))
}


path <- "."
pkg <- "mmrm"


# has a badge but it's internal
setdiff(badge(path), rd_index(path))

# is in documentation index but has no badge
setdiff(rd_index(path), badge(path))

# unexported functions in the doc index
setdiff(rd_index(path), sort(getNamespaceExports(pkg)))
setdiff(rd_index_installed(pkg), sort(getNamespaceExports(pkg)))

Try to use TMB directly to fit an MMRM and obtain Satterthwaite d.f.

Motivation: We still have trouble fitting a true MMRM (i.e. without residual variance, and obtaining correct Satterthwaite) with glmmTMB, see https://github.com/glmmTMB/glmmTMB/blob/satterthwaite_df/glmmTMB/vignettes/satterthwaite_unstructured_example2.Rmd

So one idea is to directly use TMB since then we have more freedom how to define the model. Plus TMB supports Hessian and Jacobian calculations (with latest 1.9.0 version) which should help us with the Satterthwaite d.f. calculations to avoid numDeriv::jacobian().

Material:

To do:

  • Read TMB tutorial
  • Understand the example from Ben Bolker
  • Modify towards an MMRM
    • C++ code
    • compiles
    • R code
    • debugging
    • gives right result
  • Obtain Satterthwaite d.f.
  • Use compilation with the TMBad framework
    • use intern = TRUE in MakeADFun()
      • problem is then that we don't get any beta estimates (coefficients or covariance matrix) anymore from the sdreport because it has been integrated out in C++ already. However it is really faster.
      • when we anyway want to define the covariance matrix of beta in a closed form in C++ as a function of theta in order to get the Jacobian of that, ...
      • then it would not be a big step to compute beta estimate as well at the theta ML estimates.

Add Heterogeneous Toeplitz correlation

To do:

Add function `fit_single_optimizer()`

To do:

  • See design document here
  • Add function fit_single_optimizer() in file R/fit.R
    • Modify the prototype such that also nlminb could be used
    • Don't include Nelder-Mead as an option since that does not make use of the automatic differentation in glmmTMB
  • Add unit tests in file testthat/test-fit.R
    • If needed please improve the function code
    • for the start values you can use list(theta = c(3, 0.5)) e.g. in the case of AR1 model
  • Add roxygen2 documentation chunks
    • Run Build > Document, Build > Load All, and check that documentation looks good
  • Add function name to pkgdown.yaml
  • Run Build > Check to ensure that checks pass
fit_single_optimizer <- function(formula,
                                 data,
                                 start = NULL,
                                 optimizer = c("L-BFGS-B", "BFGS", "CG", "nlminb")) 

and then inside the function:

control <- glmmTMB::glmmTMBControl(
    optimizer = if (optimizer == "nlminb") stats::nlminb else stats::optim,
    optArgs = if (optimizer == "nlminb") list() else list(method = optimizer),
    parallel = 1L
  )

Add a getter function `component()` for `mmrm_tmb` objects

Idea: Instead of replicating code across the package to e.g. look up number of subjects etc. it is better to have a getter function that can be used e.g. as component(object, "n_subjects").

To do:

  • Add component(object, name) function in https://github.com/openpharma/mmrm/blob/main/R/tmb-methods.R (although it is not an S3 method makes sense here I guess)
    • compare getS3method("getME", class = "glmmTMB") but no need to do it exactly like that
  • Look through the mmrm package and see where we are directly accessing mmrm_tmb contents.
    • e.g. object$beta_est
  • Add corresponding name option to the component function
    • e.g. name == "beta" and that will return object$beta_est
  • replace direct access code with component() calls

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.