第3章:创建Seurat对象——从原始数据到可分析对象

拿到单细胞测序的原始数据后,第一件事就是把它们装进Seurat对象。说白了,就是把表达矩阵、细胞条形码、基因信息打包成一个结构体,方便后续操作。我刚开始用Seurat时总觉得这步就是走个过场,后来发现参数没调对,后面聚类结果全歪了……嗯,咱们还是认真对待。

3.1 数据长什么样?

Seurat对象本质上是一个容器。它至少需要三样东西:

  • counts矩阵——基因×细胞,每个元素是UMI计数。通常是稀疏矩阵(dgCMatrix),别用普通稠密矩阵,否则内存直接爆炸。
  • 细胞条形码——一行一个细胞ID,比如"AAACATACAACCAC-1"。
  • 基因特征——一行一个基因名,比如"CD3D"。

最常见的来源是10X Genomics的cellranger输出。你用Read10X()读进来,返回的就是一个稀疏矩阵+两个向量。我遇到过目录结构不对导致读取失败的情况——注意filtered_feature_bc_matrix文件夹里必须包含matrix.mtx.gz、barcodes.tsv.gz、features.tsv.gz三个文件,文件名一个字母都不能错。

数据组件文件格式
表达矩阵matrix.mtx.gzMarket Exchange Format(稀疏)
细胞条形码barcodes.tsv.gz每行一个细胞ID
基因特征features.tsv.gz两列:基因ID、基因名

3.2 CreateSeuratObject核心参数

创建对象就用一个函数:CreateSeuratObject()。参数不多,但个个关键。我个人习惯把常用的几个参数列出来,避免遗漏。

library(Seurat)

# 读入10X数据
pbmc.data <- Read10X(data.dir = "filtered_gene_bc_matrices/hg19/")

# 创建Seurat对象
pbmc <- CreateSeuratObject(
  counts = pbmc.data,       # 表达矩阵(必须)
  project = "pbmc3k",       # 项目名称(建议给一个有意义的)
  min.cells = 3,            # 基因至少在3个细胞中表达才保留
  min.features = 200,       # 细胞至少表达200个基因才保留
  assay = "RNA"             # 默认assay名称(一般不改)
)

你看,关键参数就这五个。min.cells和min.features其实是做预过滤,帮你扔掉那些垃圾基因和空液滴。我建议永远不要省略它们——我见过一次项目里数据量极大,没设min.features结果保留了一堆只有几个UMI的细胞,后面归一化时直接报错。咱提前过滤掉,省心。

参数作用默认值
counts表达矩阵(稀疏矩阵最佳)无
project项目名称,用于后面合并对象时区分来源"SeuratProject"
min.cells基因至少在N个细胞中表达才保留0
min.features细胞至少表达N个基因才保留0
assay存储assay的槽位名称"RNA"
个人经验:如果你处理的是10X多组学数据(如CITE-seq),记得额外指定assay = "RNA"或自定义名称。另外,project参数在后续MergeSeurat时非常重要,千万别用默认值,否则两个样本合并后你根本分不清哪个细胞来自哪个样本。

3.3 装填元数据

Seurat对象创建后会自动生成一些元数据:nCount_RNA(每个细胞的总UMI数)和nFeature_RNA(每个细胞表达的基因数)。但你肯定还想加自己的信息,比如样本分组、批号、细胞周期评分等。可以直接用AddMetaData()添加。

# 假设你有一个data.frame,第一列是细胞ID,第二列是分组
metadata <- data.frame(
  cell_id = colnames(pbmc),
  group = c(rep("control", 1000), rep("treatment", 1000)),
  stringsAsFactors = FALSE
)
rownames(metadata) <- metadata$cell_id

pbmc <- AddMetaData(pbmc, metadata = metadata)

# 查看一下现在的元数据
head(pbmc[[]])

注意:添加元数据时,行名必须和Seurat对象中的细胞ID完全一致。我犯过低级错误——读取的细胞条形码末尾多了个"-1",合并时没对上,结果所有元数据都是NA。后来我强制用colnames()去对一遍,从此再没出过问题。

3.4 常见陷阱——创建对象的那些坑

我曾经踩过的坑:读入HDF5格式(比如10X的h5文件)时,Read10X_h5()返回的矩阵维度是基因×细胞,而CreateSeuratObject()也默认基因在行、细胞在列,这点没问题。但如果你自己构建表达矩阵(比如从scanpy导出),注意矩阵的方向——一定要基因在行、细胞在列,否则对象创建成功但后面归一化结果全是错的。建议创建后马上打印dim(pbmc)检查:行数应该是基因数,列数是细胞数。
小技巧:创建对象时,min.cells = 3和min.features = 200是一个经验值,适合10X平台10k-5k细胞的数据。如果你的数据是smart-seq2(每个细胞基因数很多但细胞数少),可以把min.features调高到500以上,min.cells设成1。你想想看,参数不是死的,要根据实际数据调整。

3.5 创建对象后的快速检查

对象创建完别急着跑下游,先看一眼基本统计。我习惯用下面几行代码快速扫一眼:

# 查看对象基本信息
pbmc

# 看一下过滤后的细胞数和基因数
dim(pbmc)

# 查看元数据列(包括自动生成的QC指标)
head(pbmc[[]])

# 绘制UMI数与基因数的关系(快速判断空液滴)
VlnPlot(pbmc, features = c("nFeature_RNA", "nCount_RNA"), ncol = 2)

运行pbmc会输出类似这样的信息:

An object of class Seurat 
13714 features across 2638 samples within 1 assay 
Active assay: RNA (13714 features, 0 variable features)
 1 layer present: counts

如果看到features数量和细胞数量符合预期,就可以放心继续了。如果数据量异常大或异常小,回查min.cells和min.features的设置。

Seurat对象创建流程 表达矩阵 (counts) 细胞条形码 基因特征 合并为 Seurat 对象 设置 min.cells 等参数 过滤低质量细胞/基因 最终 Seurat 对象 关键注意 • counts 必须为 基因×细胞矩阵 • min.features 建议 根据平台调整 • project 不要用默认