4. 数据读取与创建 Seurat 对象:Read10X 与 CreateSeuratObject 新参数

数据读取是单细胞分析的第一步,也是最容易踩坑的地方。V5 对 Read10X 和 CreateSeuratObject 都做了调整,坦白讲,改动不大,但如果你沿用 V4 的老写法,可能会跑不通。我自己迁移项目时就差点被 Read10X 的返回值给坑了——它默认返回的是一个 Seurat 对象,不是以前的稀疏矩阵。

4.1 Read10X 的变化:从“矩阵”到“对象”

在 V4 里,Read10X 返回的是 dgCMatrix 或者 list(多组样本时)。V5 改了默认行为:直接返回一个 Seurat 对象。这意味着你不需要再手动调用 CreateSeuratObject 去创建对象了。说实话,这个改动让我第一次升级时懵了几分钟。

# V4 写法
mat <- Read10X(data.dir = "filtered_feature_bc_matrix/")
seurat_obj <- CreateSeuratObject(counts = mat)

# V5 写法(直接一步到位)
seurat_obj <- Read10X(data.dir = "filtered_feature_bc_matrix/", return.object = TRUE)

注意那个 return.object = TRUE,这就是开关。如果你还想取原来的矩阵格式,可以设成 FALSE。我个人习惯在迁移旧代码时,先加这个参数,确保行为一致。

4.2 CreateSeuratObject 的新参数

V5 给 CreateSeuratObject 增加了几个实用参数,核心是两个:layer 和 assay。嗯,这里要仔细说说。

  • layer:指定数据存储层名。V5 用多层结构封装数据,默认是 "counts"。你可以在创建时就指定,省得后面手动改名。
  • assay:指定 Assay 名称,默认还是 "RNA",但如果你想提前用多组学命名,比如 "CITE" 或 "ADT",可以直接传。
# V5 创建对象示例
seurat_obj <- CreateSeuratObject(
  counts = mat,
  layer = "counts",
  assay = "RNA",
  project = "my_project",
  min.cells = 3,
  min.features = 200
)

你想想看,以前想改 assay 名还得靠 RenameAssays,现在一行搞定。不过有个细节:layer 参数并非必须,如果你省略,Seurat 会自动用 "counts"。我建议还是显式写上,让代码可读性更高。

4.3 多层数据结构带来的变化

V5 的 Seurat 对象内部存储从“单层矩阵”变成了“多层列表”。每个 Assay 里可以有多个 layer,比如 counts、data、scale.data,甚至自定义的 layer。这对下游分析影响不大,但当你直接取数据时会发现写法变了:

# V4 取 counts
mat <- GetAssayData(seurat_obj, slot = "counts")

# V5 取 counts
mat <- GetAssayData(seurat_obj, layer = "counts")

其实背后就是 slot 改成了 layer。V5 向下兼容,但会抛出警告。我建议直接改用新写法,免得以后被迫迁移。

4.4 迁移时的典型坑——我曾经…

我曾经有一个项目用 V4 跑完了全流程,代码里到处都是 @assays 和 slot = "counts"。迁移到 V5 后,Read10X 直接返回对象,但我忘记改后面的 CreateSeuratObject,结果变成了空白对象加一堆警告。排查了半天,最后发现是重复创建了对象。解决方案很简单:先检查返回值类型,再根据版本写条件分支。

# 兼容 V4 和 V5 的写法
mat_or_obj <- Read10X("path", return.object = TRUE)
if (inherits(mat_or_obj, "Seurat")) {
  seurat_obj <- mat_or_obj
} else {
  seurat_obj <- CreateSeuratObject(counts = mat_or_obj)
}

另外提醒一下:V5 的 CreateSeuratObject 默认会执行 NormalizeData 吗?不会,它只做过滤和存储,标准化得自己调。别以为升级后就自动帮你算好了。

4.5 对比表格:V4 vs V5 参数差异

功能 V4 V5
Read10X 默认返回 dgCMatrix / list Seurat 对象(需 return.object=TRUE)
创建对象时指定层 不支持 layer = "counts"
创建对象时指定 Assay 名 不支持(创建后 RenameAssays) assay = "RNA"
取 count 数据 slot = "counts" layer = "counts"
多层结构 单层 支持多个 layer

4.6 知识体系:数据读取到创建对象的完整流程

下面这张 SVG 图展示了从原始数据到 Seurat 对象的两个路径。你可以对照自己当前的版本选择走哪条路。

数据读取与创建 Seurat 对象流程 原始 10X 数据 Read10X 版本? V4:返回矩阵 CreateSeuratObject V5:返回对象 创建完成(可直接用) Seurat 对象(V5 多层) 提示:V5 的 CreateSeuratObject 新增 layer/assay 参数,创建时可一步到位,无需后续改名
提示:如果你用 Read10X 返回对象后,想用 V4 的矩阵方式继续处理,直接设 return.object = FALSE 就行。但既然升级了,建议走 V5 路线,省一步创建对象的开销。

4.7 实战建议:如何平滑迁移

  1. 先确认你的 R 包版本:packageVersion("Seurat")
  2. 在旧脚本中搜索 Read10X 和 CreateSeuratObject,替换为新参数。
  3. 跑一个测试样本,检查对象结构:str(seurat_obj) 看看是不是有 layers 列表。
  4. 如果你的代码中用了 GetAssayData 和 slot,改成 layer,避免 warning 堆积。
避坑:别在同一个工作流里混用 V4 和 V5 的对象。我遇到过用 V5 创建的对象传给 V4 的归一化函数,结果报错说找不到 scale.data。最好统一升级或保持一个版本。

说白了,数据读取这一步迁移成本很低,最怕的是不注意默认行为的变化。把 return.object 和 layer 这两个点记牢,后面就顺了。