library(CGNM)
#> Warning: replacing previous import 'lifecycle::last_warnings' by
#> 'rlang::last_warnings' when loading 'tibble'
#> Warning: replacing previous import 'lifecycle::last_warnings' by
#> 'rlang::last_warnings' when loading 'pillar'
To illutrate the use of CGNM here we illustrate how CGNM can be used to estiamte two sets of the best fit parameters of the pharmacokinetics model when the drug is administered orally (known as flip-flop kinetics). To illustrate that the model can be definied flexibly, we use the RxODE package to define the model.
library(RxODE)
#> Warning: package 'RxODE' was built under R version 4.0.5
#> RxODE 1.1.5 using 1 threads (see ?getRxThreads)
#> no cache: create with `rxCreateCache()`
#> ========================================
#> RxODE has not detected OpenMP support and will run in single-threaded mode
#> This is a Mac. Please read https://mac.r-project.org/openmp/
#> ========================================
="
model_textd/dt(X_1)=-ka*X_1
d/dt(C_2)=(ka*X_1-CL_2*C_2)/V1"
# here the model defined as above is compiled
=RxODE(model_text)
model#> ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin18/8.2.0'
#> ld: warning: ignoring file /usr/local/gfortran/lib/libquadmath.dylib, building for macOS-x86_64 but attempting to link with file built for macOS-arm64
#> ld: warning: ignoring file /usr/local/gfortran/lib/libgfortran.dylib, building for macOS-x86_64 but attempting to link with file built for macOS-arm64
# here we define the model function where takes in the parameter vector x and return the model simulation
=function(x){
model_function
=c(0.1,0.2,0.4,0.6,1,2,3,6,12)
observation_time
<- c(ka=x[1],V1=x[2],CL_2=x[3])
theta <- eventTable()
ev $add.dosing(dose = 1000, start.time =0)
ev$add.sampling(observation_time)
ev=model$solve(theta, ev)
odeSollog10(odeSol[,"C_2"])
}
=log10(c(4.91, 8.65, 12.4, 18.7, 24.3, 24.5, 18.4, 4.66, 0.238)) observation
Here we have specified the upper and lower range of the initial guess.
=Cluster_Gauss_Newton_method(nonlinearFunction=model_function,
CGNM_resulttargetVector = observation,
initial_lowerRange = c(0.1,0.1,0.1),initial_upperRange = c(10,10,10))
#> [1] "checking if the nonlinearFunction can be evaluated at the initial_lowerRange"
#> [1] "Evaluation Successful"
#> [1] "checking if the nonlinearFunction can be evaluated at the initial_upperRange"
#> [1] "Evaluation Successful"
#> [1] "checking if the nonlinearFunction can be evaluated at the (initial_upperRange+initial_lowerRange)/2"
#> [1] "Evaluation Successful"
#> [1] "Generating initial cluster. 212 out of 250 done"
#> [1] "Generating initial cluster. 247 out of 250 done"
#> [1] "Generating initial cluster. 249 out of 250 done"
#> [1] "Generating initial cluster. 250 out of 250 done"
#> [1] "Iteration:1 Median sum of squares residual=5.25955407888962"
#> [1] "Iteration:2 Median sum of squares residual=2.88924898056518"
#> [1] "Iteration:3 Median sum of squares residual=1.04957650552473"
#> [1] "Iteration:4 Median sum of squares residual=0.870934437573875"
#> [1] "Iteration:5 Median sum of squares residual=0.415738073333175"
#> [1] "Iteration:6 Median sum of squares residual=0.12392179350789"
#> [1] "Iteration:7 Median sum of squares residual=0.0195858623507722"
#> [1] "Iteration:8 Median sum of squares residual=0.00860993045234649"
#> [1] "Iteration:9 Median sum of squares residual=0.00747674517663476"
#> [1] "Iteration:10 Median sum of squares residual=0.00735090860878783"
#> [1] "Iteration:11 Median sum of squares residual=0.00734935214333789"
#> [1] "Iteration:12 Median sum of squares residual=0.00734926727698233"
#> [1] "Iteration:13 Median sum of squares residual=0.00734926723765412"
#> [1] "Iteration:14 Median sum of squares residual=0.0073492672302981"
#> [1] "Iteration:15 Median sum of squares residual=0.00734926722840556"
#> [1] "Iteration:16 Median sum of squares residual=0.00734926720679642"
#> [1] "Iteration:17 Median sum of squares residual=0.00734926720434712"
#> [1] "Iteration:18 Median sum of squares residual=0.00734926720273257"
#> [1] "Iteration:19 Median sum of squares residual=0.00734926720255589"
#> [1] "Iteration:20 Median sum of squares residual=0.00734926720039642"
#> [1] "Iteration:21 Median sum of squares residual=0.00734926718966226"
#> [1] "Iteration:22 Median sum of squares residual=0.00734926718817224"
#> [1] "Iteration:23 Median sum of squares residual=0.00734926718370376"
#> [1] "Iteration:24 Median sum of squares residual=0.0073492671797677"
#> [1] "Iteration:25 Median sum of squares residual=0.00734926717468603"
head(acceptedApproximateMinimizers(CGNM_result))
#> [,1] [,2] [,3]
#> [1,] 0.5179077 10.66123 9.877165
#> [2,] 0.9265002 19.07196 9.877318
#> [3,] 0.5178996 10.66104 9.877274
#> [4,] 0.5178916 10.66071 9.877374
#> [5,] 0.5178949 10.66083 9.877325
#> [6,] 0.9265107 19.07215 9.877352
=Cluster_Gauss_Newton_Bootstrap_method(CGNM_result, nonlinearFunction=model_function)
CGNM_bootstrap#> [1] "checking if the nonlinearFunction can be evaluated at the initial_lowerRange"
#> [1] "Evaluation Successful"
#> [1] "checking if the nonlinearFunction can be evaluated at the initial_upperRange"
#> [1] "Evaluation Successful"
#> [1] "checking if the nonlinearFunction can be evaluated at the (initial_upperRange+initial_lowerRange)/2"
#> [1] "Evaluation Successful"
#> [1] "Generating initial cluster. 200 out of 200 done"
#> [1] "Iteration:1 Median sum of squares residual=0.0127671994504241"
#> [1] "Iteration:2 Median sum of squares residual=0.0122083575490302"
#> [1] "Iteration:3 Median sum of squares residual=0.0113845407288297"
#> [1] "Iteration:4 Median sum of squares residual=0.0111062224623181"
#> [1] "Iteration:5 Median sum of squares residual=0.0108952109605084"
#> [1] "Iteration:6 Median sum of squares residual=0.0108951753684889"
#> [1] "Iteration:7 Median sum of squares residual=0.0108951753684889"
#> [1] "Iteration:8 Median sum of squares residual=0.0108951753684889"
#> [1] "Iteration:9 Median sum of squares residual=0.0108951753684889"
#> [1] "Iteration:10 Median sum of squares residual=0.0108951750250479"
#> [1] "Iteration:11 Median sum of squares residual=0.0108951750250479"
#> [1] "Iteration:12 Median sum of squares residual=0.0108951750109662"
#> [1] "Iteration:13 Median sum of squares residual=0.0108951750109662"
#> [1] "Iteration:14 Median sum of squares residual=0.0108951750109662"
#> [1] "Iteration:15 Median sum of squares residual=0.0108951750020855"
#> [1] "Iteration:16 Median sum of squares residual=0.0108951750020855"
#> [1] "Iteration:17 Median sum of squares residual=0.0108951750020855"
#> [1] "Iteration:18 Median sum of squares residual=0.0108951750020855"
#> [1] "Iteration:19 Median sum of squares residual=0.0108951749921072"
#> [1] "Iteration:20 Median sum of squares residual=0.0108951749921072"
#> [1] "Iteration:21 Median sum of squares residual=0.0108951749921072"
#> [1] "Iteration:22 Median sum of squares residual=0.0108951749921072"
#> [1] "Iteration:23 Median sum of squares residual=0.0108951749921072"
#> [1] "Iteration:24 Median sum of squares residual=0.0108951749921049"
#> [1] "Iteration:25 Median sum of squares residual=0.0108951749921049"
To use the plot functions the user needs to manually load ggplot2.
library(ggplot2)
#>
#> Attaching package: 'ggplot2'
#> The following object is masked from 'package:RxODE':
#>
#> facet_wrap
Despite the robustness of the algorithm not all approximate minimizers converge so here we visually inspect to see how many of the approximate minimizers we consider to have the similar SSR to the minimum SSR. Currently the algorithm automatically choose “acceptable” approximate minimizer based on Grubbs’ Test for Outliers. If for whatever the reason this criterion is not satisfactly the users can manually set the indicies of the acceptable approximat minimizers.
plot_Rank_SSR(CGNM_result)
plot_paraDistribution_byHistogram(CGNM_bootstrap, ParameterNames=c("Ka","V1","CL_2"), ReparameterizationDef=c("x1","x2","x3"), bins = 50)
plot_goodnessOfFit(CGNM_result, plotType = 1, independentVariableVector = c(0.1,0.2,0.4,0.6,1,2,3,6,12), plotRank = seq(1,50))
plot_goodnessOfFit(CGNM_bootstrap, plotType = 1, independentVariableVector = c(0.1,0.2,0.4,0.6,1,2,3,6,12))
For the complete description and comparison with the conventional algorithm please see (https: //doi.org/10.1007/s11081-020-09571-2):
Aoki, Y., Hayami, K., Toshimoto, K., & Sugiyama, Y. (2020). Cluster Gauss–Newton method. Optimization and Engineering, 1-31.
Cluster Gauss-Newton method is an algorithm for obtaining multiple minimisers of nonlinear least squares problems \[ \min_{\boldsymbol{x}}|| \boldsymbol{f}(\boldsymbol x)-\boldsymbol{y}^*||_2^{\,2} \] which do not have a unique solution (global minimiser), that is to say, there exist \(\boldsymbol x^{(1)}\neq\boldsymbol x^{(2)}\) such that \[ \min_{\boldsymbol{x}}|| \boldsymbol{f}(\boldsymbol x)-\boldsymbol{y}^*||_2^{\,2}=|| \boldsymbol{f}(\boldsymbol x^{(1)})-\boldsymbol{y}^*||_2^{\,2}=|| \boldsymbol{f}(\boldsymbol x^{(2)})-\boldsymbol{y}^*||_2^{\,2} \,. \] Parameter estimation problems of mathematical models can often be formulated as nonlinear least squares problems. Typically these problems are solved numerically using iterative methods. The local minimiser obtained using these iterative methods usually depends on the choice of the initial iterate. Thus, the estimated parameter and subsequent analyses using it depend on the choice of the initial iterate. One way to reduce the analysis bias due to the choice of the initial iterate is to repeat the algorithm from multiple initial iterates (i.e. use a multi-start method). However, the procedure can be computationally intensive and is not always used in practice. To overcome this problem, we propose the Cluster Gauss-Newton method (CGNM), an efficient algorithm for finding multiple approximate minimisers of nonlinear-least squares problems. CGN simultaneously solves the nonlinear least squares problem from multiple initial iterates. Then, CGNM iteratively improves the approximations from these initial iterates similarly to the Gauss-Newton method. However, it uses a global linear approximation instead of the Jacobian. The global linear approximations are computed collectively among all the iterates to minimise the computational cost associated with the evaluation of the mathematical model.