Skip to contents

Overview

lstparsR reads NONMEM .lst listing files and extracts parameter estimates into tidy tibbles. It is designed for population pharmacokinetic and pharmacodynamic (PK/PD) workflows where many model runs need to be parsed programmatically.

Key design choices:

  • Parameter output is returned as tibbles with consistent column names.
  • Missing optional quantities (e.g., standard errors when the covariance step is absent) are NA. Missing required parameter sections raise errors; fetch_all() catches these, warns, and returns NULL for failed elements.
  • Both VECTOR blocks (THETA) and lower-triangular MATRIX blocks (OMEGA, SIGMA) are handled, including multi-line parameter sets.

Reading a Listing File

Use read_lst_file() to load a .lst file into an S3 object of class "lst":

path <- system.file("testdata", "full_cov.lst", package = "lstparsR")
lst  <- read_lst_file(path)
lst
#> <lst> NONMEM listing file: 1321 lines
summary(lst)
#> <lst> NONMEM listing file
#>   Lines            : 1321
#>   Estimation method: FIRST ORDER CONDITIONAL ESTIMATION WITH INTERACTION
#>   Covariance step  : TRUE

The lst object is simply a character vector (one element per line) with class "lst" attached. All fetch_* functions require this class.

Extracting THETA (Fixed Effects)

fetch_thetas(lst)
#> # A tibble: 12 × 4
#>    parameter     estimate       se     rse
#>    <chr>            <dbl>    <dbl>   <dbl>
#>  1 TH_1          34.1     3.37e+ 0 9.88e 0
#>  2 TH_2      387000       5.41e+ 7 1.40e 4
#>  3 TH_3           8.05    5.2 e- 1 6.46e 0
#>  4 TH_4           1.78    1.49e- 1 8.37e 0
#>  5 TH_5           0.498   2.78e- 2 5.58e 0
#>  6 TH_6           0.362   4.81e- 1 1.33e 2
#>  7 TH_7          -0.171   1.35e- 1 7.89e 1
#>  8 TH_8          -0.0314  2.69e- 1 8.57e 2
#>  9 TH_9          -0.163   2.78e- 1 1.71e 2
#> 10 TH10          -0.23    1.88e- 1 8.17e 1
#> 11 TH11           0.00539 1.98e- 2 3.67e 2
#> 12 TH12           0.2     1.90e+74 9.50e76

Each row corresponds to one THETA parameter. The se and rse columns contain the standard error and relative standard error (as a percentage), respectively.

Use the digits argument to round RSE values:

fetch_thetas(lst, digits = 1)
#> # A tibble: 12 × 4
#>    parameter     estimate       se     rse
#>    <chr>            <dbl>    <dbl>   <dbl>
#>  1 TH_1          34.1     3.37e+ 0 9.9 e 0
#>  2 TH_2      387000       5.41e+ 7 1.40e 4
#>  3 TH_3           8.05    5.2 e- 1 6.5 e 0
#>  4 TH_4           1.78    1.49e- 1 8.4 e 0
#>  5 TH_5           0.498   2.78e- 2 5.6 e 0
#>  6 TH_6           0.362   4.81e- 1 1.33e 2
#>  7 TH_7          -0.171   1.35e- 1 7.89e 1
#>  8 TH_8          -0.0314  2.69e- 1 8.57e 2
#>  9 TH_9          -0.163   2.78e- 1 1.71e 2
#> 10 TH10          -0.23    1.88e- 1 8.17e 1
#> 11 TH11           0.00539 1.98e- 2 3.67e 2
#> 12 TH12           0.2     1.90e+74 9.50e76

Extracting OMEGA (Random Effects)

fetch_etas() extracts the diagonal of the OMEGA covariance matrix, plus ETA shrinkage when reported:

fetch_etas(lst)
#> # A tibble: 7 × 5
#>   parameter estimate        se      rse shrinkage
#>   <chr>        <dbl>     <dbl>    <dbl>     <dbl>
#> 1 ETA1       0.2      3.89e- 2  1.94e 1      5.08
#> 2 ETA2       0.255    4.63e- 2  1.82e 1      1.62
#> 3 ETA3       0.1      2   e+73  2   e76    100   
#> 4 ETA4       0.1      1.99e+73  1.99e76    100   
#> 5 ETA5       0.00001  6.85e+68  6.85e75     97.6 
#> 6 ETA6       0.00001 NA        NA           99.0 
#> 7 ETA7       0.00001 NA        NA           97.0

Shrinkage values can be rounded separately:

fetch_etas(lst, digits = 1, shk_digits = 1)
#> # A tibble: 7 × 5
#>   parameter estimate        se      rse shrinkage
#>   <chr>        <dbl>     <dbl>    <dbl>     <dbl>
#> 1 ETA1       0.2      3.89e- 2  1.94e 1       5.1
#> 2 ETA2       0.255    4.63e- 2  1.82e 1       1.6
#> 3 ETA3       0.1      2   e+73  2   e76     100  
#> 4 ETA4       0.1      1.99e+73  1.99e76     100  
#> 5 ETA5       0.00001  6.85e+68  6.85e75      97.6
#> 6 ETA6       0.00001 NA        NA            99  
#> 7 ETA7       0.00001 NA        NA            97

Extracting SIGMA (Residual Error)

fetch_sigmas(lst)
#> # A tibble: 2 × 4
#>   parameter estimate      se    rse
#>   <chr>        <dbl>   <dbl>  <dbl>
#> 1 EPS1        0.0769 0.00434   5.64
#> 2 EPS2        0.123  0.199   162.

Objective Function Value

fetch_ofv(lst)
#> [1] 8986.318

For failed runs, fetch_ofv() falls back to the workflow footer (OFV = ...) if the standard #OBJV: line is absent.

Condition Number

The condition number is computed as the ratio of the largest to smallest eigenvalue of the correlation matrix of parameter estimates. Values above 1000 suggest numerical instability:

fetch_condn(lst)
#> [1] 23.30882

All at Once

fetch_all() runs every parser in a single call. Individual parser failures are caught and returned as NULL with a warning, so a single problematic section does not abort the entire extraction:

result <- fetch_all(lst)
names(result)
#> [1] "thetas" "etas"   "sigmas" "ofv"    "condn"
result$thetas
#> # A tibble: 12 × 4
#>    parameter     estimate       se     rse
#>    <chr>            <dbl>    <dbl>   <dbl>
#>  1 TH_1          34.1     3.37e+ 0 9.88e 0
#>  2 TH_2      387000       5.41e+ 7 1.40e 4
#>  3 TH_3           8.05    5.2 e- 1 6.46e 0
#>  4 TH_4           1.78    1.49e- 1 8.37e 0
#>  5 TH_5           0.498   2.78e- 2 5.58e 0
#>  6 TH_6           0.362   4.81e- 1 1.33e 2
#>  7 TH_7          -0.171   1.35e- 1 7.89e 1
#>  8 TH_8          -0.0314  2.69e- 1 8.57e 2
#>  9 TH_9          -0.163   2.78e- 1 1.71e 2
#> 10 TH10          -0.23    1.88e- 1 8.17e 1
#> 11 TH11           0.00539 1.98e- 2 3.67e 2
#> 12 TH12           0.2     1.90e+74 9.50e76
result$ofv
#> [1] 8986.318
result$condn
#> [1] 23.30882

Runs Without a Covariance Step

When NONMEM did not run or complete a covariance step, SE, RSE, and condition number are returned as NA:

path2 <- system.file("testdata", "theta_without_cov.lst", package = "lstparsR")
lst2  <- read_lst_file(path2)
fetch_thetas(lst2)
#> # A tibble: 12 × 4
#>    parameter     estimate    se   rse
#>    <chr>            <dbl> <dbl> <dbl>
#>  1 TH_1          34.1        NA    NA
#>  2 TH_2      387000          NA    NA
#>  3 TH_3           8.05       NA    NA
#>  4 TH_4           1.78       NA    NA
#>  5 TH_5           0.498      NA    NA
#>  6 TH_6           0.362      NA    NA
#>  7 TH_7          -0.171      NA    NA
#>  8 TH_8          -0.0314     NA    NA
#>  9 TH_9          -0.163      NA    NA
#> 10 TH10          -0.23       NA    NA
#> 11 TH11           0.00539    NA    NA
#> 12 TH12           0.2        NA    NA
fetch_condn(lst2)
#> [1] NA

Batch Processing

A common pattern is to parse many .lst files at once:

library(purrr)

lst_files <- list.files("models/", pattern = "\\.lst$", full.names = TRUE)

results <- map(lst_files, \(f) {
  lst <- read_lst_file(f)
  fetch_all(lst)
})

# Combine all THETA tables
all_thetas <- map_dfr(results, "thetas", .id = "run")

Estimation Headers and Output Layouts

lstparsR recognizes the following NONMEM estimation method headers:

  • First Order (FO)
  • First Order Conditional Estimation (FOCE)
  • First Order Conditional Estimation with Interaction (FOCE-I)
  • Stochastic Approximation Expectation-Maximization (SAEM)
  • Importance Sampling (IMP)
  • Importance Sampling Assisted by Mode A Posteriori (IMPMAP)
  • Markov Chain Monte Carlo Bayesian Analysis

Numerical regression tests cover FOCE-I listings and controlled edge cases; FO listings have additional execution coverage. Recognizing a method header does not validate every layout or posterior summary from that method. The parsers expect the fixed-format result sections shown in the examples. Compare results with the original listing for unfamiliar layouts. Parsing does not validate the scientific model or its estimates.

Interactive Exploration

For interactive use, launch the built-in Shiny application:

lstparsR::run_app()

This opens a browser-based interface where you can upload .lst files, view parsed results in tables, and download them as CSV or RDS.