数据导入:三种常见格式的读法与检查
数据读入,说白了就是整个分析流程的「地基」。地基没打牢,后面所有花哨的聚类、降维都是白搭。我自己刚开始接触单细胞时,就因为读错了一个格式,整整调试了两天。
咱们这章就专门解决这个问题。你拿到一份单细胞数据,无非就是三种常见格式:10X Genomics 的标准输出、H5 文件、或者 CSV 表格。每一种我都踩过坑,咱们一个一个过。
1. 10X Genomics 格式:最正统,但也最容易出错
10X Genomics 的标准输出有三个核心文件。少了任何一个,Seurat 都不认。我个人习惯是拿到数据后先检查文件夹结构是不是下面这样:
sample_dir/
├── barcodes.tsv.gz # 细胞条形码
├── features.tsv.gz # 基因特征(以前叫 genes.tsv)
└── matrix.mtx.gz # 表达量矩阵
嗯,这里要注意。老版本 10X 输出的是 genes.tsv,新版本改成了 features.tsv。Seurat 的 Read10X 函数两个都支持,但你最好确认一下版本,避免后续基因注释出问题。
读取方式很简单:
library(Seurat)
data_dir <- "path/to/sample_dir"
counts <- Read10X(data.dir = data_dir)
# 检查读进来的对象
dim(counts) # 看看多少行(基因)x 列(细胞)
class(counts) # 应该是 dgCMatrix
head(rownames(counts)) # 检查基因名
genes.tsv,v3 的叫 features.tsv。你如果只写死一种文件名,读 v3 数据时能正常跑,但读 v2 就可能报错。我的解决方案是在读取前统一重命名,或者用条件判断来加载。
2. H5 格式:一个文件搞定,但读取参数要注意
H5 格式现在越来越常见。它把所有信息打包成一个文件,管理起来比三个文件方便。但方便归方便,有两个参数你必须在读之前确认一下。
先看 H5 文件的结构。你用 h5ls 或者 R 的 hdf5r 包看一下就清楚了:
# 用命令行检查 H5 内容
h5ls filtered_feature_bc_matrix.h5
# 输出大概是这样的
# /matrix Group
# /matrix/barcodes Dataset {10000}
# /matrix/data Dataset {5000000, 2}
# /matrix/features Group
# /matrix/features/id Dataset {33694}
# /matrix/features/name Dataset {33694}
在 R 里面读取:
library(Seurat)
counts <- Read10X_h5(filename = "filtered_feature_bc_matrix.h5")
# 注意:默认读的是 'matrix' 组。如果你的文件结构不同,需要指定 group
Read10X_h5 默认只读 matrix 这个组。但有些自定义的 H5 文件,数据结构可能不是标准命名。我建议你在读之前先用 h5ls 看一眼内部结构。
另外,H5 文件也分 filtered(过滤后)和 raw(原始)两种版本。千万别把 raw 的数据当 filtered 用,否则后面你会看到几十万个细胞,里面全是空的。
3. CSV 格式:最灵活,但坑最多
CSV 格式的来源五花八门。有些是直接从测序公司拿到的,有些是公共数据库里下载的,甚至可能是你自己写脚本生成的。我个人的经验是:读 CSV 之前,先搞清楚它的「朝向」。
是基因在行、细胞在列?还是反过来?Seurat 默认接受的是「基因在行、细胞在列」。如果你的数据是反的,必须转置。
举个例子。我拿到过一个 CSV 文件,看起来是这样:
# 常见格式:基因在行,细胞在列
,cell_1,cell_2,cell_3
GENE_A,12,0,5
GENE_B,0,8,0
GENE_C,3,2,10
读取方式:
library(Seurat)
raw_data <- read.csv("expression_matrix.csv", row.names = 1)
# 检查维度
dim(raw_data)
# 如果你的数据是细胞在行、基因在列,需要转置
# raw_data <- t(raw_data)
# 然后创建 Seurat 对象
seurat_obj <- CreateSeuratObject(counts = raw_data, project = "my_project")
read.csv 读进来后,第一列全成了行名,但第一行多了一列全是 NA。那个 NA 列后来导致 Seurat 在计算 QC 指标时报错,查了好久才发现是读入时头文件没处理好。解决办法是读完后手动删除空列,或者用 check.names = FALSE 来避免自动修正。
4. 数据检查:别急着往下跑,先验证
数据读进来了,别急着创建对象或开始降维聚类。我建议你先做三件事,确保数据质量没问题。
| 检查项 | 常见问题 | 我的处理方式 |
|---|---|---|
| 维度核对 | 基因数或细胞数异常 | 对比实验设计或参考数据集;如果基因数少于5000或细胞数异常多/少,先排查原因 |
| Barcode ID 格式 | 末尾带 -1、-2 等后缀,表示做过合并 | 确认样本合并时的命名规则;用 gsub 统一处理后缀 |
| 基因名重复 | 同一基因出现多次,或出现非标准符号 | 用 table(duplicated(rownames(x))) 检查;必要时用 avereps 去重 |
举个例子。你如果用 Read10X 读了多个样本合并后的数据,barcode 末尾会带着 -1、-2 这样的标签:
# 检查 barcode 格式
head(colnames(counts))
# 输出:AAACCCAAGAAACTCA-1 AAACCCACAGTTCTCT-1 AAACCCAGTCTGGTCA-2
gsub("-\\d$", "", colnames(counts)) 把后缀去掉,这样可以统一处理。但要注意,如果你的项目里同一个 barcode 出现在多个样本中,去掉后缀会导致混淆,这时就别去。
核心流程:一张图搞清楚
下面这张图帮你理清楚三种格式的读取路径以及共用的检查步骤。你可以把它当作实战时的检查清单:
你看看这张图:不管从哪个格式出发,最后都要汇聚到「数据检查」这个关键节点。维度、barcode、基因名,三个检查一个都不能少。我每次分析新数据,都会按这个流程走一遍,能避免掉 90% 的后期报错。
01_data_check.R 脚本,把上面的检查步骤全部写成函数。这样每次新项目或新样本进来,直接跑一遍这个脚本,就能快速确认数据是否可用。