# Generate BLQ observations and fit different error models

In this example we will demonstrate generating and fitting to BLQ data using the ~rectnorm() distribution with a simple depot + one compartment model as follows:-

Fig. 45 One compartment model with depot dosing used to generate and fit BLQ PK data.

Note

See the Depot + One compartment PK with BLQ obtained by the PoPy developers for this example, including input script and output data file.

## Generating BLQ observations

The PREDICTIONS section to create BLQ data utilises the ~rectnorm() distribution, as follows:-

    PREDICTIONS: |
        p[DV_CENTRAL] = s[CENTRAL]/m[V1]
        var = m[ANOISE]**2 + m[PNOISE]**2 * p[DV_CENTRAL]**2
        # c[DV_CENTRAL] ~ norm(p[DV_CENTRAL], var)
        c[DV_CENTRAL] ~ rectnorm(p[DV_CENTRAL], var, LLQ=0.5)

This creates observations with a LLQ of 0.5, see Table 34.

Table 34 Generated observations + true underlying model PK curves for first three individuals

Notice that no observations are output below 0.5, as expected. PoPy outputs observations of 0.5, if the generated observation is in the interval [-inf, 0.5].

## Fitting BLQ observations using rectnorm (correct error model)

We fit the same (correct) error model, using the same PREDICTIONS section as follows:-

    PREDICTIONS: |
        p[DV_CENTRAL] = s[CENTRAL]/m[V1]
        var = m[ANOISE]**2 + m[PNOISE]**2 * p[DV_CENTRAL]**2
        # c[DV_CENTRAL] ~ norm(p[DV_CENTRAL], var)
        c[DV_CENTRAL] ~ rectnorm(p[DV_CENTRAL], var, LLQ=0.5)

i.e. a ~rectnorm() distribution, with a LLQ of 0.5. Note that, this fitting method does not require the LAPLACE objective function, we can use the FOCE objective function instead in PoPy.

See Table 35 for PK curves after fitting.

Table 35 Fitted model PK curves vs true model PK curves for first three individuals

Note that the fitted curves (solid blue) line are estimated to be below the LLQ level of 0.5 at later time points.

The estimated `f[X]` compared to the true `f[X]` are shown in Table 36 and Table 37.

Table 36 Comparison of initial, fitted and true `f[X]` main values
Name | Initial | Fitted | True | Prop. Error | Abs. Error
--- | --- | --- | --- | --- | ---
f[KA] | 1 | 0.195 | 0.2 | 2.28% | 4.55e-03
f[CL] | 1 | 2.03 | 2 | 1.27% | 2.54e-02
f[V1] | 20 | 47 | 50 | 6.06% | 3.03e+00

Table 37 Comparison of initial, fitted and true `f[X]` noise values
Name | Initial | Fitted | True | Prop. Error | Abs. Error
--- | --- | --- | --- | --- | ---
f[PNOISE] | 0.1 | 0.139 | 0.15 | 7.41% | 1.11e-02

Table 36 and Table 37 show that the `f[KA], f[CL], f[V1], f[PNOISE]` parameters are recovered well when fitting with ~rectnorm() distribution.

The full set of fitted `f[X]` variable is shown below:-

    f[KA] = 0.1954
    f[CL] = 2.0254
    f[V1] = 46.9680
    f[KA_isv,CL_isv,V1_isv] = [
        [ 0.1374, 0.0157, 0.0621 ],
        [ 0.0157, 0.0392, 0.0200 ],
        [ 0.0621, 0.0200, 0.1254 ],
    ]
    f[PNOISE] = 0.1389
    f[ANOISE] = 0.0100

These fitted values can be compared with fitting alternative error models below.

## Fitting BLQ observations using norm (incorrect error model)

Note

See the Depot One Comp PK with BLQ observations set to LLQ script and results used by the PoPy developers for this example.

We fit a (incorrect) error model which treats observations of LLQ as actual 0.5 observations, using a ~norm() distribution, as follows:-

    PREDICTIONS: |
        p[DV_CENTRAL] = s[CENTRAL]/m[V1]
        var = m[ANOISE]**2 + m[PNOISE]**2 * p[DV_CENTRAL]**2
        c[DV_CENTRAL] ~ norm(p[DV_CENTRAL], var)
        # c[DV_CENTRAL] ~ rectnorm(p[DV_CENTRAL], var, LLQ=0.5)

For fitted curves see Table 38.

Table 38 Fitted model ~norm() distribution error curves vs LLQ model PK curves for first three individuals

Note that the fitted curves (solid blue) line try to stay close to the BLQ values at 0.5, which is incorrect, as the PK curve should approach zero concentration instead.

The fitted `f[X]` values are:-

    f[KA] = 2.6741
    f[CL] = 0.9560
    f[V1] = 86.0580
    f[KA_isv,CL_isv,V1_isv] = [
        [ 1.1328, -0.0132, 0.2360 ],
        [ -0.0132, 0.0002, -0.0028 ],
        [ 0.2360, -0.0028, 0.0504 ],
    ]
    f[PNOISE] = 0.2288
    f[ANOISE] = 0.0100

These fitted values are inaccurate compared to the parameters recovered using the ~rectnorm() distribution in section Fitting BLQ observations using rectnorm (correct error model) above.

## Fitting BLQ observations using half LLQ (approx error model)

Note

See the Depot One Comp PK with BLQ observations set to 0.5*LLQ script and results used by the PoPy developers for this example.

We fit a simple approx BLQ error model, which models observations of LLQ as bare 0.5* LLQ observations, by preprocessing the original observation data, as follows:-

    PREPROCESS: |
        # use halve value blq data
        if c[DV_CENTRAL] <= 0.5 and c[TYPE] == 'obs':
            c[DV_CENTRAL] = 0.25

The ~norm() distribution is used to model these amended observations (similar to Fitting BLQ observations using norm (incorrect error model) above), see:-

    PREDICTIONS: |
        p[DV_CENTRAL] = s[CENTRAL]/m[V1]
        var = m[ANOISE]**2 + m[PNOISE]**2 * p[DV_CENTRAL]**2
        c[DV_CENTRAL] ~ norm(p[DV_CENTRAL], var)
        # c[DV_CENTRAL] ~ rectnorm(p[DV_CENTRAL], var, LLQ=0.5)

For fitted curves using this half LLQ approximation, see Table 39.

Table 39 Fitted model ~norm() distribution error curves vs half LLQ model PK curves for first three individuals

Note that the fitted curves (solid blue) line get closer to zero (the true asymptotic concentration) as time increases, but are still heavily distorted by assuming the half LLQ values are true observations.

The fitted `f[X]` values are:-

    f[KA] = 1.3656
    f[CL] = 1.6576
    f[V1] = 80.4195
    f[KA_isv,CL_isv,V1_isv] = [
        [ 0.7858, 0.0888, 0.2165 ],
        [ 0.0888, 0.0103, 0.0250 ],
        [ 0.2165, 0.0250, 0.0610 ],
    ]
    f[PNOISE] = 0.3307
    f[ANOISE] = 0.0100

These fitted values are similar to the results obtained in Fitting BLQ observations using norm (incorrect error model) and also inaccurate compared to the parameters recovered using the ~rectnorm() distribution in section Fitting BLQ observations using rectnorm (correct error model) above.

## Fit to non-BLQ observations only (reduced data model)

Note

See the Depot One Comp PK ignoring BLQ observations. script and results used by the PoPy developers for this example.

We can also just ignore the BLQ data, by using PREPROCESS to remove the LLQ observations, as follows:-

    PREPROCESS: |
        # ignore blq data
        if c[DV_CENTRAL] <= 0.5 and c[TYPE] == 'obs':
            return

The ~norm() distribution is then used to model the above LLQ observations only, see:-

    PREDICTIONS: |
        p[DV_CENTRAL] = s[CENTRAL]/m[V1]
        var = m[ANOISE]**2 + m[PNOISE]**2 * p[DV_CENTRAL]**2
        c[DV_CENTRAL] ~ norm(p[DV_CENTRAL], var)
        # c[DV_CENTRAL] ~ rectnorm(p[DV_CENTRAL], var, LLQ=0.5)

The fitted curves are shown in Table 40.

Table 40 Fitted model ~norm() distribution error curves vs ignore BLQ model PK curves for first three individuals

Note that curves are fitted to the above LLQ observations only, i.e. earlier time points, but there is no data for later LLQ time points.

The fitted `f[X]` values are:-

    f[KA] = 0.2310
    f[CL] = 1.8489
    f[V1] = 52.3484
    f[KA_isv,CL_isv,V1_isv] = [
        [ 0.0000, 0.0002, 0.0004 ],
        [ 0.0002, 0.0400, 0.0068 ],
        [ 0.0004, 0.0068, 0.0991 ],
    ]
    f[PNOISE] = 0.1494
    f[ANOISE] = 0.0100

These fitted values are much better then the Fitting BLQ observations using norm (incorrect error model) and Fitting BLQ observations using half LLQ (approx error model) approximatons, but not quite as accurate as the ~rectnorm() distribution results in section Fitting BLQ observations using rectnorm (correct error model).