Context
Last week, I was discussing about how to use nls()
for a specific
model with one of my colleague and I ended creating a piece of code to
show what I was talking about! Even though there are many posts exploring nls()
in more depth that I did (for instance this post on datascienceplus by Lionel Herzog),
I thought I could share these lines of command here!
Basically, we were talking about a model where the temperature (\(T\)
) follows
a saturation curve starting from 10°C at t=0 (so T(0) = 10) and plateauing at \(T_{\inf}\)
.
$$T(t) = T_{\inf} - (T_{\inf} - T_0)\exp(-kt)$$
Goal and data
The goal here is to use nls()
(Nonlinear Least Squares) to find \(k\)
and \(T_{inf}\)
.
For the sack of clarity, I simulate the data, i.e. I use the saturation curve
with known parameter values, then I add some noise (here a white noise):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
library(magrittr)
# Parameters
## known
T0 = 10
## the ones we are looking for
k = 0.2
Tinf = 20
# Simulate data
## time
seqt <- seq(0, 50, .25)
## create a data frame
simdata <- cbind(
seqt = seqt,
sim = Tinf - (Tinf- T0) * exp(-k * seqt) + .5 * rnorm(length(seqt))
) %>% as.data.frame
head(simdata)
#R> seqt sim
#R> 1 0.00 9.847264
#R> 2 0.25 11.458372
#R> 3 0.50 10.958598
#R> 4 0.75 10.449508
#R> 5 1.00 11.965725
#R> 6 1.25 12.796043
|
Use nls()
Now I call nls()
to fit the data:
1
|
res <- nls(sim ~ Tinf - (Tinf - 10)*exp(-k*seqt), simdata, list(Tinf = 1, k = .1))
|
All the information needed are stored in res
and display via the print method:
1
2
3
4
5
6
7
8
9
10
|
res
#R> Nonlinear regression model
#R> model: sim ~ Tinf - (Tinf - 10) * exp(-k * seqt)
#R> data: simdata
#R> Tinf k
#R> 20.0542 0.1926
#R> residual sum-of-squares: 49.17
#R>
#R> Number of iterations to convergence: 8
#R> Achieved convergence tolerance: 6.446e-08
|
Let’s draw a quick plot:
1
2
3
4
5
|
## get the coefficients values
cr <- coef(res)
fitC <- function(x) cr[1] - (cr[1] - 10)*exp(-cr[2]*x)
plot(simdata[,1], simdata[,2], xlab = "Time (min)", ylab = "Temperature (°C)")
curve(fitC, 0, 50, add = TRUE, col = "#2f85a4", lwd = 3)
|
That’s all folks!
Display information relative to the R session used to render this post.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
sessionInfo()
#R> R version 4.4.2 (2024-10-31)
#R> Platform: x86_64-pc-linux-gnu
#R> Running under: Ubuntu 22.04.5 LTS
#R>
#R> Matrix products: default
#R> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#R> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0
#R>
#R> locale:
#R> [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8 LC_COLLATE=C.UTF-8
#R> [5] LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8 LC_PAPER=C.UTF-8 LC_NAME=C
#R> [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
#R>
#R> time zone: UTC
#R> tzcode source: system (glibc)
#R>
#R> attached base packages:
#R> [1] stats graphics grDevices utils datasets methods base
#R>
#R> other attached packages:
#R> [1] magrittr_2.0.3 inSilecoRef_0.1.1
#R>
#R> loaded via a namespace (and not attached):
#R> [1] sass_0.4.9 utf8_1.2.4 generics_0.1.3 xml2_1.3.6 blogdown_1.19
#R> [6] stringi_1.8.4 httpcode_0.3.0 digest_0.6.37 evaluate_1.0.1 bookdown_0.41
#R> [11] fastmap_1.2.0 plyr_1.8.9 jsonlite_1.8.9 backports_1.5.0 crul_1.5.0
#R> [16] promises_1.3.0 fansi_1.0.6 jquerylib_0.1.4 bibtex_0.5.1 cli_3.6.3
#R> [21] shiny_1.9.1 rlang_1.1.4 cachem_1.1.0 yaml_2.3.10 tools_4.4.2
#R> [26] dplyr_1.1.4 httpuv_1.6.15 DT_0.33 rcrossref_1.2.0 curl_6.0.0
#R> [31] vctrs_0.6.5 R6_2.5.1 mime_0.12 lifecycle_1.0.4 stringr_1.5.1
#R> [36] fs_1.6.5 htmlwidgets_1.6.4 miniUI_0.1.1.1 pkgconfig_2.0.3 bslib_0.8.0
#R> [41] pillar_1.9.0 later_1.3.2 glue_1.8.0 Rcpp_1.0.13-1 xfun_0.49
#R> [46] tibble_3.2.1 tidyselect_1.2.1 knitr_1.49 xtable_1.8-4 htmltools_0.5.8.1
#R> [51] rmarkdown_2.29 compiler_4.4.2
|