第3章:单细胞数据格式——你每天都在打交道的东西
说实话,单细胞数据分析第一步,就是把数据读进来。但这第一步,新手最容易栽跟头。
我记得刚入行时,师兄丢给我一个文件夹,里面一堆.mtx、.tsv、.gz文件,我愣是不知道哪是哪。后来自己踩过几次坑,才算真正搞明白这些格式的脾气。
这一章,我就把四种最常见的单细胞数据格式给你讲透:10X Genomics的官方格式(mtx + barcodes + features)、H5AD、H5、CSV。每种格式的来历、结构、用哪个API读、什么时候选哪个,咱们一次性说清楚。
10X Genomics 标准输出:三件套
10X Genomics 平台是目前单细胞数据的主力军。它跑完 Cell Ranger 后,会吐出三个文件:
matrix.mtx—— 稀疏矩阵,保存表达量barcodes.tsv—— 细胞条形码列表(每个barcode对应一列)features.tsv(或genes.tsv) —— 基因注释(每行一个基因)
这三兄弟缺一不可。我遇到过有人只拷了matrix.mtx回来,结果没法跑后续分析——少了细胞和基因的信息。
关键提醒:10X格式本质是Market Exchange Format(MTX),专门存稀疏矩阵。因为单细胞数据里绝大多数元素是0(比如一个细胞里检测到3000个基因已经很密集了),用全矩阵存你会崩溃——一个10万细胞的矩阵存下来得几十GB。MTX只记录非零元素的行、列、值,省空间省内存。
怎么读?
Scanpy 提供了专门的读取函数:
import scanpy as sc
# 经典用法,传入包含三文件的文件夹路径
adata = sc.read_10x_mtx('path/to/filtered_feature_bc_matrix/')
# 或者指定文件名
adata = sc.read_10x_mtx(
'path/to/matrix.mtx',
var_names='gene_symbols',
cache=True
)
它会自动找到barcodes.tsv和features.tsv。不过要注意,如果你的文件命名不是标准名,你需要手动指定gzipped=False或使用sc.read_mtx再加两步拼接。
我曾经踩过的坑:Cell Ranger 2.x 时代用 genes.tsv,3.x之后改成了 features.tsv,而且多了第三列(比如Gene Expression / Antibody Capture)。如果你拿着旧版barcodes文件对新版MTX,会跳错。建议养成习惯:拿到数据先 ls -la 检查文件名,确认版本。
H5AD:Scanpy的亲生儿子
H5AD(AnnData HDF5格式)是Scanpy官方推荐的存储格式。它用HDF5容器把Anndata对象的全部结构(X矩阵、obs、var、uns、obsm等)打包到一个文件里。说白了,就是整个分析中间状态都可以存下来,下次直接恢复。
个人习惯:每次跑完一个关键步骤(比如QC、归一化、聚类),我都用 adata.write('step2_qc.h5ad') 存一下。这样万一后面跑崩了,不用从头再来。H5AD支持压缩,20万细胞的h5ad大致150-300 MB,比存CSV集群小一个数量级。
读取更简单:
adata = sc.read_h5ad('my_data.h5ad')
# 然后就可以直接看adata.obs、adata.var
你想想看,一个文件搞定所有,比三件套省心多少。但H5AD也有一些限制:它是二进制格式,不能直接用Excel打开看。如果你只是想快速查看一小部分基因的表达,可能不如CSV方便。
H5:另一种HDF5风味
有些人会把h5格式的文件混进来,比如filtered_feature_bc_matrix.h5。这个其实是10X官方提供的另一种输出,内部储存方式和H5AD类似,但结构不同。它用的是10X自己定义的HDF5 schema,里面包含matrix、barcodes、features等group。
Scanpy可以读:
adata = sc.read_10x_h5('filtered_feature_bc_matrix.h5')
注意这个函数不会自动生成var_names,你需要查看adata.var['gene_ids']是ENSEMBL ID还是Gene Symbol。如果只有ID,你可能需要额外做个基因注释映射。我个人很少用这种格式,因为变量名容易混乱,而且不如h5ad灵活。
CSV:通用但笨重的老将
CSV(或TSV)是最通用的格式,可以直接用Excel、R、Python的pandas读。单细胞社区里常用的是两种变体:
- 表达量矩阵CSV —— 行是细胞,列是基因,或者转置。通常很大,不适合大矩阵。
- 元数据CSV —— 存样本信息、细胞注释等,分析中经常配合使用。
如果你手头只有CSV表达矩阵,可以用pandas读,再转Anndata:
import pandas as pd
import anndata as ad
df = pd.read_csv('expression.csv', index_col=0)
adata = ad.AnnData(X=df.values, obs=pd.DataFrame(index=df.index), var=pd.DataFrame(index=df.columns))
# 注意:此时X是稠密矩阵,内存开销大
避坑指南:我曾经帮同事转一个20万细胞×3万基因的CSV,pandas.read_csv直接吃掉了20 GB RAM,中途还卡死。后来我建议他从源头用10X格式读,再转h5ad。能用稀疏格式就不要用稠密CSV——尤其是单细胞数据。
四种格式对比一览
| 格式 | 核心文件 | 稀疏支持 | 兼容性 | 推荐场景 |
|---|---|---|---|---|
| 10X三件套 | matrix.mtx / barcodes.tsv / features.tsv | 是(MTX) | Scanpy、Seurat、通用 | 原始数据输入、批量处理 |
| H5AD | 单个.h5ad文件 | 是(默认) | Scanpy最佳,Seurat需转换 | 中间状态保存、项目归档 |
| 10X H5 | 单个.h5文件 | 是 | Scanpy、Seurat原生 | 10X官方输出,直接读取 |
| CSV | 单个.csv/.tsv | 否(稠密) | 几乎所有软件 | 小数据集、元数据、跨工具交互 |
我自己的选择策略
做了几年单细胞分析,我形成了这样的习惯:
- 输入阶段:如果数据是10X跑出来的,直接读10X三件套。如果是别人给的,先问有没有h5ad——没有的话,先转成h5ad再继续。
- 分析过程中:每一步存h5ad。QC完存一个,归一化完存一个,聚类完存一个。H5AD的压缩和读取速度都很快。
- 输出给合作者:如果是同行,给h5ad。如果是临床医生或非生信人员,我会导出关键结果(marker基因、聚类表)为CSV,方便他们用Excel打开。
为什么会这样?因为分析中间状态往往包含大量uns对象里的分类颜色、聚类层次结构、umap坐标——这些东西CSV很难优雅表达。而h5ad原生支持,存完恢复几乎零成本。
本章知识结构
小结:读数据前先确认格式
明白了这些格式的脾气,下次拿到新数据后,你就知道该怎么起了。记住一个原则:能用稀疏格式就别用稠密的,能用二进制就别用文本的(除非需要人眼直接看)。