7  分析灵敏度

7.1 分析目的

分析灵敏度(analytical sensitivity)描述测量系统在低浓度端区分”信号与噪声”的能力,由三个递进的 限值构成:

  • LoB(Limit of Blank,空白限):空白样本可能出现的最高测值(95% 分位数)。
  • LoD(Limit of Detection,检出限):能以 95% 置信水平区分于空白的最低浓度
  • LoQ(Limit of Quantitation,定量限):测量结果达到预设精密度目标(如 CV = 20%)的最低浓度

本文演示如何使用 ivdtools 包的 lob_lod_loq() 依据 CLSI EP17-A2 计算分析灵敏度:

  • LoB 按 5.3.3.1 参数法:LoB = M_B + cp·SD_B,将全部空白结果合并为池,cp = 1.645/√(1 − 1/(4(B−K))) 为小样本修正的 95% 单侧分位数(B 为空白结果总数、K 为空白样本数)。
  • LoD 按 5.4.3:先对非空白低浓度样本拟合 Sadler 精度轮廓模型(方差随浓度),再自 LoB 起做 固定点迭代 X = LoB + cp·SD_WL(X)cp = 1.645/√(1 − 1/(4(N_TOT−K)))
  • LoQ 按附录 D1 Example 1(功能灵敏度):求精度轮廓与目标 CV 水平线的交点 √Var(X)/X = target_cv。该 LoQ 仅反映精密度、不含偏差

示例数据为确定性的教学数据,仅用于演示流程;正式研究必须依据方案或标准预先规定的实验设计、 目标浓度与接受标准。

代码
library(ivdtools)
library(readr)

7.2 函数概述

函数 主要用途 关键输入或输出
lob_lod_loq() 一次计算 LoB / LoD / LoQ 汇总数据、空白样本名、目标 CV
replicate_to_mean() 汇总重复测量 均值、SD、重复数 n
fit_equation() 拟合 Sadler 精度轮廓(内部调用) eq="sadler"df_col
print() / plot() 结果展示 表格式汇总、SD/CV 双面板

lob_lod_loq() 的输入是已汇总的 data.frame:每行一个样本,含样本名称列、均值列(即浓度)、 SD 列与重复数 n 列,列名可自由指定。它内部自动完成 Sadler 最优模型拟合,无需用户手动拟合。

7.3 示例:LoB / LoD / LoQ 分析

7.3.1 读取和核验数据

数据包含 2 个空白样本(blank_A、blank_B)与 6 个低浓度样本(L1–L6),各样本重复测量 (空白各 40 次、低浓度各 30 次),共 260 行。SD 随浓度升高而增大,符合低浓度端”方差随均值增大”的常见情形:

代码
sens <- read_csv("./data/sensitivity.csv", show_col_types = FALSE)
sens <- as.data.frame(sens)
str(sens)
'data.frame':   260 obs. of  2 variables:
 $ sample: chr  "blank_A" "blank_A" "blank_A" "blank_A" ...
 $ value : num  0.024 -0.006 0.055 -0.072 0.057 -0.023 -0.05 0.003 0.051 0.029 ...
代码
dim(sens)
[1] 260   2
代码
table(sens$sample)

blank_A blank_B      L1      L2      L3      L4      L5      L6 
     40      40      30      30      30      30      30      30 

7.3.2 逐样本汇总

replicate_to_mean() 按样本名称分组计算均值、SD 与重复数(分组变量为字符时保留原值, 两个空白各占一行):

代码
rep <- replicate_to_mean(data.frame(x = sens$sample, y = sens$value),
                         x = "x", y = "y")
rep$sample <- rep$x
rep$mean   <- rep$y_mean
rep$sd     <- rep$y_sd
rep$n      <- rep$y_n
rep[c("sample", "mean", "sd", "n")]

注意: lob_lod_loq() 要求方差模型响应为方差、并按自由度加权,因此汇总后还需给每行补 var = sd^2df = n − 1 两列,再交给 lob_lod_loq()。若你的数据已含这两列则无需此步。

7.3.3 计算 LoB / LoD / LoQ

blank 参数指定空白样本名称(可多个),target_cv 指定 LoQ 的精密度目标:

代码
summ <- rep[c("sample", "mean", "sd", "n")]
res <- lob_lod_loq(summ, sample_col = "sample", mean_col = "mean",
                   sd_col = "sd", n_col = "n",
                   blank = c("blank_A", "blank_B"), target_cv = 0.20)
res
Limit of Blank / Detection / Quantitation (EP17-A2)
Precision profile: Sadler; best model = Model_3
  Equation            : sigma^2 = b1 + b2 * mu^2
  Parameters          : b1 = 0.010196, b2 = 0.010388
  Fit                 : AIC = -479.4; RSS = 0.08315; GoF p = 0.9437
  LoB  (parametric, B = 80, K = 2) : 0.08357
  LoD  (fixed-point)                : 0.2552
  LoQ  (CV = 20%)                    : 0.5868
Note: LoQ is based on precision ONLY; bias is not included.

结果解读:

  • LoB = 0.0836:空白测值的 95% 分位数(参数法),合并 B = 80 个空白结果、K = 2 个空白样本。
  • LoD = 0.26:精度轮廓上 X = LoB + cp·SD(X) 的固定点,即高于此浓度的测值可判为”非空白”。
  • LoQ = 0.59(CV = 20%):达到 20% 精密度目标所需的最低浓度,仅基于精密度

7.3.4 返回对象结构

lob_lod_loq() 返回 sensitivity 对象,各限值与参数以命名分量保存:

代码
str(res, max.level = 1)
List of 13
 $ call     : language lob_lod_loq(data = summ, sample_col = "sample", mean_col = "mean", sd_col = "sd",      n_col = "n", blank = c("bl| __truncated__
 $ lob      : num 0.0836
 $ lod      : num 0.255
 $ loq      : num 0.587
 $ n_blank  : int 80
 $ B        : int 80
 $ K        : int 2
 $ target_cv: num 0.2
 $ cp_lob   : num 1.65
 $ cp_lod   : num 1.65
 $ fit      :List of 12
  ..- attr(*, "class")= chr "fit_equation"
 $ model    : chr "Model_3"
 $ notes    : chr(0) 
 - attr(*, "class")= chr "sensitivity"
代码
res$lob
[1] 0.0835705
代码
res$lod
[1] 0.2552205
代码
res$loq
[1] 0.5867594
代码
res$B
[1] 80
代码
res$K
[1] 2
代码
res$cp_lob
[1] 1.647643
代码
res$cp_lod
[1] 1.646183
代码
res$model
[1] "Model_3"

cp_lobcp_lod 即 EP17 的两个小样本修正系数;model 为 AIC 选出的最优 Sadler 模型 (本例为模型 3,混合方差型)。

7.3.5 图形

plot() 画出 SD 与 CV 两个精度轮廓面板,叠加 LoB / LoD / LoQ 参考线,直观展示各限值的 几何含义:

代码
plot(res)

7.4 其他输入情形

7.4.1 情形一:仅空白(只算 LoB)

若无低浓度水平,则只计算 LoB,LoD / LoQ 为 NA

代码
res_b <- lob_lod_loq(summ[summ$sample %in% c("blank_A", "blank_B"), ],
                     sample_col = "sample", mean_col = "mean",
                     sd_col = "sd", n_col = "n",
                     blank = c("blank_A", "blank_B"))
res_b
Limit of Blank / Detection / Quantitation (EP17-A2)
  LoB  (parametric, B = 80, K = 2) : 0.08357
  LoD  (fixed-point)                : --
  LoQ  (CV = 20%)                    : --
Note: LoQ is based on precision ONLY; bias is not included.

7.4.2 情形二:无空白(只算 LoQ)

若无空白样本(blank = NULL),则只计算 LoQ,LoB / LoD 为 NA

代码
res_q <- lob_lod_loq(summ[!summ$sample %in% c("blank_A", "blank_B"), ],
                     sample_col = "sample", mean_col = "mean",
                     sd_col = "sd", n_col = "n")
res_q
Limit of Blank / Detection / Quantitation (EP17-A2)
Precision profile: Sadler; best model = Model_3
  Equation            : sigma^2 = b1 + b2 * mu^2
  Parameters          : b1 = 0.010196, b2 = 0.010388
  Fit                 : AIC = -479.4; RSS = 0.08315; GoF p = 0.9437
  LoB  (parametric, B = 0, K = 0) : --
  LoD  (fixed-point)                : --
  LoQ  (CV = 20%)                    : 0.5868
Note: LoQ is based on precision ONLY; bias is not included.

7.4.3 情形三:LoQ < LoD

当按目标 CV 算出的 LoQ 低于 LoD 时(如空白噪声大、低浓度端精密度好),LoQ 会取 max(LoQ, LoD) 并以警告提示,保证 LoQ ≥ LoD

代码
# 构造"空白噪声大、低浓度精密度好"的数据
d_noisy <- data.frame(
  sample = c("blank", paste0("L", 1:6)),
  mean   = c(0, 0.5, 1, 2, 5, 10, 20),
  sd     = c(5, sqrt(0.01 + 0.02 * c(0.5, 1, 2, 5, 10, 20)^2)),
  n      = c(30L, rep(5L, 6))
)
res_n <- lob_lod_loq(d_noisy, sample_col = "sample", mean_col = "mean",
                     sd_col = "sd", n_col = "n", blank = "blank")
res_n
Limit of Blank / Detection / Quantitation (EP17-A2)
Precision profile: Sadler; best model = Model_3
  Equation            : sigma^2 = b1 + b2 * mu^2
  Parameters          : b1 =   0.01, b2 =   0.02
  Fit                 : AIC = -469.2; RSS = 2.924e-29; GoF p =     1
  LoB  (parametric, B = 30, K = 1) : 8.261
  LoD  (fixed-point)                : 10.79
  LoQ  (CV = 20%)                    : 10.79
Note: LoQ is based on precision ONLY; bias is not included.
  Note: LoQ (precision) < LoD; LoQ reported as LoD = 10.79.

7.5 结果判读要点

  1. 目标先定:分析前确定目标 CV(本文 20% 仅为教学示例)、置信水平与接受标准。
  2. 空白合并池:LoB 将全部空白结果合并计算,cpB−K 自由度修正,样本量小时不可忽略。
  3. LoQ 仅含精密度:本流程的 LoQ 不包含偏差,不能替代基于总误差(TE)的定量限声明。
  4. 模型选择:不同 Sadler 模型在低浓度端外推差异大,报告应注明 AIC 最优模型与排序。
  5. LoQ ≥ LoD:程序保证 LoQ 不低于 LoD;若按 CV 计算的 LoQ 低于 LoD,会以警告并取 max
  6. 数据格式lob_lod_loq() 的输入为已汇总 data.frame,原始的重复测量数据需先由replicate_to_mean()处理。