数据准备误区:忽略数据标准化、不处理缺失值、数据范围不一致导致视觉偏差

做图表最怕什么?数据还没准备好,就急着出图。我在项目里见过太多人,拿到数据点几下鼠标就扔进工具里生成堆叠图、热力图……结果图是出来了,但里面的坑一个比一个深。今天咱们专门聊聊数据准备阶段的三个常见误区,说白了就是:没标准化、没处理缺失值、数据范围没对齐。

这三个问题如果没解决,丰度图表基本就是废的。视觉上可能好看,但结论全是错的。我自己踩过不少坑,后来总结了一套排查方法,咱们一个一个说。

误区一:忽略数据标准化

丰度数据经常来自不同批次、不同实验或不同测序深度。直接拿原始值画图,相当于把苹果和橙子放在一起比重量——根本没法比。

举个例子:A样品测序深度100万条reads,B样品只有20万条。A样品里某个丰度值500,B样品里某个丰度值100。单看数值,A是B的5倍。但标准化之后(比如每百万条reads的丰度),A可能是500,B可能是500。完全不一样。这就是没标准化的后果。

我个人习惯,拿到数据第一件事就是问:这个丰度值,是原始值还是已经标准化过了?如果没有,马上做标准化。

常用标准化方法

方法适用场景说明
CPM (Counts Per Million)RNA-seq、scRNA-seq每百万reads中的count数,消除测序深度差异
TPM (Transcripts Per Million)转录组定量结合基因长度和测序深度,更准确
RPKM/FPKM基因表达每百万reads每千碱基,注意方向性
分位数归一化多组比较使多个样品的分布一致,消除批次效应
Z-score热力图、聚类均值0,标准差1,突出相对变化
⚠️ 注意: 选择标准化方法时要考虑数据特点。比如,Z-score会把正负值都压到统一尺度,但会丢失原始丰度信息。热力图用Z-score没问题,堆叠柱状图就得用相对比例。

我遇到过最典型的案例:某个项目做了宏基因组分析,不同样本的测序深度差了一个数量级。同事直接拿原始计数做堆叠柱状图,看着A样品里某个菌占60%,B样品里占10%。其实标准化后,两个样品那个菌的比例都是15%左右。嗯,那次被审稿人直接问住,后来再也不敢跳过标准化了。

误区二:不处理缺失值

丰度数据里缺失值非常常见——有些物种在部分样本里没检测到,某些基因在特定条件下不表达。但很多工具和脚本遇到缺失值就报错,或者默默把它当成0处理。这就出大问题了。

我曾经排查过一个散点图,发现某组数据有好多点在零点附近密集分布。查了半天,原来是缺失值被填充成了0。实际上这些点应该是“无数据”,而不是“丰度为0”。这俩完全是两码事。

处理缺失值的常见方式

  • 直接删除:如果缺失比例小(<5%),可以整行或整列删除。但小心别把关键样本删了。
  • 填充为0:适用于明确表示“未检测到”的场景。但必须标注清楚。
  • 填充为极小值:比如用最小检测限的一半。适合后续做log转换,避免-Inf。
  • 插值填充:用均值、中位数、或邻近值填补。适合连续变量,但会引入偏差。
  • 保留为NA:一些可视化工具支持跳过NA,比如ggplot2的na.rm=TRUE。
💡 我的习惯: 在数据清洗阶段,我会单独记录缺失值情况。出图前检查一遍:sum(is.na(data)) 看看还有多少NA。如果真的必须填充,我用一个突出颜色标注填充点(比如在散点图上用不同颜色标记填充值),这样观众知道这些点的数据是推算的。

代码示例:检查并处理缺失值

# R语言示例
# 检查每列的缺失值数量
colSums(is.na(abundance_data))

# 如果缺失<5%,直接删除对应行
cleaned_data <- na.omit(abundance_data)

# 如果需要填充为极小值(比如1e-6)
min_val <- min(abundance_data[!is.na(abundance_data)], na.rm = TRUE) / 10
cleaned_data[is.na(abundance_data)] <- min_val

# 绘图时跳过NA
ggplot(cleaned_data, aes(x = sample, y = abundance)) +
  geom_point(na.rm = TRUE)  # 注意这个参数
避坑指南: 我曾经用过一段脚本,默认把NA填充成0,然后画热力图。结果一大片蓝色区域(低值)其实是缺失值,根本不是真正的低丰度。后来我养成了习惯:在做任何图之前,先看看数据框里有没有NA。有的话问一句:是故意保留还是该填充?

误区三:数据范围不一致导致视觉偏差

这个坑特别隐蔽。假设有两组丰度数据:A组0~1000,B组0~1。你如果直接画在同一个坐标轴上,B组的数据几乎会压缩成一条线,根本看不到细节。反过来,如果使用不同的缩放尺度,又可能误判组间差异。

我记得有次做降维后的散点图,两个主成分解释方差差了一个数量级。我没做缩放,直接画出来,点的分布完全是扁的。后来用了scale()标准化之后,才看出真正的聚类结构。

常见的范围不一致情况

  • 不同技术平台:qPCR vs RNA-seq,数值范围差好几个数量级。
  • 不同批次:实验条件细微差异导致整体偏移。
  • 不同数据类型:绝对丰度 vs 相对比例,数值尺度完全不同。
  • 不同样本类型:组织样本 vs 细胞样本,含量差异大。

排查表格:如何判断数据范围是否一致

检查项方法异常信号
总体范围range(data)最小值/最大值相差几个数量级
每列的范围每列的min/max某列最大值为另一列的100倍以上
每行的范围按行统计最大值/最小值存在极端离群值导致其余值被压扁
变异系数每列 CV = sd/meanCV 超过 100%(即 sd > mean)
⚠️ 特别注意: 热力图如果不对行或列做归一化,高丰度基因会完全盖过低丰度基因,整个图只能看到几个亮点。我个人建议:热力图一定做行(或列)Z-score归一化。堆叠柱状图则一定要确保各列加起来是100%(相对比例)。

那怎么解决呢?简单说:统一尺度。常用的方法有:

  • 缩放到[0,1]区间:(x - min(x)) / (max(x) - min(x))
  • Z-score标准化:(x - mean(x)) / sd(x)
  • 对于丰度数据,log转换很常用:log2(x + 1) 可以压缩大值,放大小值的差异。

数据准备阶段的核心流程

我整理了一个流程图,把上面三个误区串起来。每次做图前按这个走一遍,能避免80%的坑。

数据准备阶段检查流程 原始丰度数据 步骤1: 检查缺失值 缺失值如何处置? 删除/填充极小值/保留NA (一定要标注!) 步骤2: 检查数据范围 范围是否一致? 需不需要归一化/标准化? (CPM/TPM/Z-score...) ✅ 检查无误,可出图

这张图总结了我每次做丰度图之前的检查流程。先处理缺失值,再检查数据范围是否一致,最后决定用哪种标准化方法。你想想看,大部分坑都是因为跳过了其中某一步。按这个流程走,至少能保证数据本身没问题。

💡 最终提醒: 以上三个误区,其实都指向同一个核心原则:图表呈现的是数据规律,而不是数据本身。如果不做标准化,看到的可能是测序深度差异;不处理缺失值,看到的可能是填充偏差;范围不一致,看到的可能是缩放假象。做图之前,先问自己一句:这个图想表达什么?数据真的准备好了吗?