如何使用 cvms 可视化 confusion matrix 中的 FPR 和 TPR?
建议用 ggplot2 画分面热图,直接比较这 16 个 FPR、TPR 数值。现有的 test 只有汇总指标,无法还原包含 TP、FP、TN、FN 计数的混淆矩阵。
如果对每种变异类型分别做二分类评估,就有 2 种策略 × 2 种测序技术 × 2 种变异类型 = 8 个评估组合,对应 8 个混淆矩阵。这些矩阵可以合并到一张图中,不必分别生成 8 张图片。
FPR、TPR 与混淆矩阵的区别
假设正类表示“存在目标类型的变异”,混淆矩阵如下:
| 真实类别 \ 预测类别 | 阳性 | 阴性 |
|---|---|---|
| 阳性 | TP | FN |
| 阴性 | FP | TN |
FPR 和 TPR 的计算公式为:
[ \mathrm{TPR}=\frac{TP}{TP+FN},\qquad \mathrm{FPR}=\frac{FP}{FP+TN} ]
TPR 是召回率,也称 sensitivity;FPR 是假阳性率。两者的分母不同,因此不需要相加等于 1。
仅凭这两个比例,无法确定各格的实际计数。还需要真实阳性总数 (P) 和真实阴性总数 (N),才能计算:
[ TP=\mathrm{TPR}\times P,\qquad FN=(1-\mathrm{TPR})\times P ]
[ FP=\mathrm{FPR}\times N,\qquad TN=(1-\mathrm{FPR})\times N ]
如果比例已经四舍五入,反推的计数可能有误差,应优先使用原始计数。
用四个分面展示现有数据
可以将 SNV、INDEL 分成两行,将 FPR、TPR 分成两列。每个分面内,横轴区分 linear、graph,纵轴区分 PacBio、Illumina。
这样,一张图就能展示全部结果:四个面板,每个面板包含四个色块。这是指标热图,横纵轴表示实验配置。
运行题目中创建 test 的代码后,执行:
library(ggplot2)
plot_data <- test
plot_data$Strategy <- factor(
plot_data$Strategy,
levels = c("linear", "graph")
)
plot_data$Approach <- factor(
plot_data$Approach,
levels = c("Illumina", "PacBio")
)
plot_data$Type <- factor(
plot_data$Type,
levels = c("snv", "indel"),
labels = c("SNV", "INDEL")
)
plot_data$Predictor <- factor(
plot_data$Predictor,
levels = c("FPR", "TPR")
)
ggplot(
plot_data,
aes(x = Strategy, y = Approach, fill = Value)
) +
geom_tile(colour = "white", linewidth = 0.8) +
geom_text(
aes(label = sprintf("%.1f%%", 100 * Value)),
colour = "black",
size = 4
) +
facet_grid(
Type ~ Predictor,
labeller = labeller(
Predictor = c(
FPR = "FPR(越低越好)",
TPR = "TPR(越高越好)"
)
)
) +
scale_fill_gradient(
low = "#f7fbff",
high = "#6baed6",
limits = c(0, 1),
labels = scales::label_percent(accuracy = 1),
name = "指标值"
) +
coord_equal() +
labs(
x = "策略",
y = "测序技术",
caption = "颜色表示数值大小;FPR 越低越好,TPR 越高越好。"
) +
theme_minimal(base_size = 12) +
theme(
panel.grid = element_blank(),
strip.text = element_text(face = "bold")
)
所有分面共用 0–1 的色标,便于比较数值。颜色越深表示数值越大:TPR 越大通常越好,FPR 越大则越差。
例如,在提供的 PacBio SNV 数据中,graph 的 FPR 更低,TPR 也更高。热图中的数值标注可以直接呈现这两个差异:
| 策略 | FPR | TPR |
|---|---|---|
| linear | 39.0% | 75.0% |
| graph | 33.5% | 86.5% |
用四宫格展示归一化混淆矩阵
如果需要四宫格形式,且 FPR、TPR 符合上述定义,可以构造按真实类别归一化的矩阵:
| 真实类别 \ 预测类别 | 阳性 | 阴性 |
|---|---|---|
| 阳性 | TPR | (1-\mathrm{TPR}) |
| 阴性 | FPR | (1-\mathrm{FPR}) |
每行之和为 1。这种图能展示检出、漏检、误报和正确排除的比例,但无法展示样本数量或类别占比。
以下代码为每个评估组合生成一个四宫格,将 8 个四宫格放在同一张图中:
library(tidyr)
library(ggplot2)
rates <- pivot_wider(
test,
id_cols = c(Approach, Strategy, Type),
names_from = Predictor,
values_from = Value
)
normalized_cm <- rbind(
transform(
rates,
Truth = "Positive",
Prediction = "Positive",
Rate = TPR
),
transform(
rates,
Truth = "Positive",
Prediction = "Negative",
Rate = 1 - TPR
),
transform(
rates,
Truth = "Negative",
Prediction = "Positive",
Rate = FPR
),
transform(
rates,
Truth = "Negative",
Prediction = "Negative",
Rate = 1 - FPR
)
)
normalized_cm$Truth <- factor(
normalized_cm$Truth,
levels = c("Negative", "Positive")
)
normalized_cm$Prediction <- factor(
normalized_cm$Prediction,
levels = c("Positive", "Negative")
)
normalized_cm$Type <- factor(
normalized_cm$Type,
levels = c("snv", "indel"),
labels = c("SNV", "INDEL")
)
ggplot(
normalized_cm,
aes(x = Prediction, y = Truth, fill = Rate)
) +
geom_tile(colour = "white", linewidth = 0.8) +
geom_text(
aes(label = sprintf("%.1f%%", 100 * Rate)),
size = 3.5
) +
facet_grid(Approach + Strategy ~ Type) +
scale_fill_gradient(
low = "#f7fbff",
high = "#6baed6",
limits = c(0, 1),
labels = scales::label_percent(accuracy = 1),
name = "行内比例"
) +
coord_equal() +
labs(
x = "预测类别",
y = "真实类别",
caption = "按真实类别归一化,每行合计 100%;色块不表示计数。"
) +
theme_minimal(base_size = 12) +
theme(panel.grid = element_blank())
这里对 SNV 和 INDEL 分别评估。如果将二者定义为互斥类别,要构造多分类混淆矩阵,还需要它们之间的误分类计数。当前数据没有这些信息。
什么时候使用 cvms
拿到每组实际的 TP、FN、FP、TN 后,可以使用 cvms::plot_confusion_matrix() 绘图。每组输入整理为三列:真实类别、预测类别和对应计数。
输入结构如下,运行前需将 TP、FN、FP、TN 赋为该组的实际计数:
cm_counts <- data.frame(
Target = factor(
c("Positive", "Positive", "Negative", "Negative"),
levels = c("Positive", "Negative")
),
Prediction = factor(
c("Positive", "Negative", "Positive", "Negative"),
levels = c("Positive", "Negative")
),
N = c(TP, FN, FP, TN)
)
cvms::plot_confusion_matrix(
cm_counts,
target_col = "Target",
prediction_col = "Prediction",
counts_col = "N"
)
计数列应使用实际计数,不能直接填入 FPR、TPR,也不能随意假设样本总数来推算。现有指标表用 ggplot2 就能展示,分面也能清楚表达分组关系,无须使用嵌套色块。
绘图前确认指标定义
评估变异检测结果时,要特别确认 FPR 的分母。如果实际计算的是:
[ \frac{FP}{TP+FP} ]
这个指标是 FDR(false discovery rate),即 (1-\mathrm{precision}),不能标为 FPR。还需明确负类的定义,并确认不同方法是否使用一致的评估区域和匹配规则,否则图中的数值未必能直接比较。
如果想比较 FPR 与 TPR 的取舍,也可以按 SNV、INDEL 分面,画横轴为 FPR、纵轴为 TPR 的散点图,用颜色和形状区分策略与测序技术。当前每个组合只有一个点,只能展示工作点;要画 ROC 曲线,还需要多个阈值下的 FPR、TPR。
备注:内容仅供参考。
