单细胞学习(14)—— Seurat → Scanpy 多个样本的分析流程
Scanpy 处理多个样本的分析流程(对比 Seurat)
本学习笔记整理了在 Scanpy 处理多个样本的完整分析流程,并对比 Seurat 的对应功能,包括 数据读取、批次整合、降维聚类、UMAP 参数调整、可重复性保证 等关键环节。
1. 读取多个样本并合并
在 Seurat 中,我们可以用 Read10X()
读取多个样本,并用 merge()
或 IntegrateData()
进行合并。
Seurat:
# 读取多个样本数据
sample1 <- Read10X("path/to/sample1/filtered_feature_bc_matrix")
sample2 <- Read10X("path/to/sample2/filtered_feature_bc_matrix")
seurat_obj1 <- CreateSeuratObject(counts = sample1, project = "sample1")
seurat_obj2 <- CreateSeuratObject(counts = sample2, project = "sample2")
# 合并对象
seurat_obj <- merge(seurat_obj1, y = seurat_obj2, add.cell.ids = c("sample1", "sample2"))
在 Scanpy,可以使用 sc.read_10x_mtx()
逐个读取样本,并用 sc.concat()
进行合并。
Scanpy(推荐方式):
import scanpy as sc
import os
sample_dirs = ["sample1", "sample2", "sample3", "sample4", "sample5", "sample6", "sample7", "sample8"]
adatas = []
for sd in sample_dirs:
path = os.path.join("/data", sd, "filtered_feature_bc_matrix")
ad = sc.read_10x_mtx(path, var_names='gene_symbols')
ad.obs["sample"] = sd # 添加样本名
adatas.append(ad)
# 合并样本
adata = sc.concat(adatas, label='sample', keys=sample_dirs, index_unique='-')
Scanpy(另一种方法 concatenate()
):
adata = adatas[0].concatenate(adatas[1:], join='outer')
🔹 sc.concat()
vs. concatenate()
对比
方法 | sc.concat() (推荐) | concatenate() (旧方法) |
---|---|---|
批量合并多个对象 | ✅ 支持 sc.concat(adatas) | ❌ 必须 adatas[0].concatenate(adatas[1:]) |
自动添加样本名 | ✅ label='sample' | ❌ 只会创建 batch (默认 0,1,2…) |
**支持 **index_unique | ✅ 可以设置 index_unique='-' | ❌ 无法控制索引格式 |
基因合并策略 | ✅ join='outer' 或 join='inner' | ✅ join='outer' 或 join='inner' |
推荐使用 | ✅ 适用于大规模数据,更加灵活 | ❌ 适用于简单拼接(不推荐) |
✅ 对比: Seurat 使用
merge()
,而 Scanpy 推荐使用sc.concat()
进行样本合并。concatenate()
是较旧的方法,不建议用于多个样本的批量整合。
1. 读取多个样本并合并
在 Seurat 中,我们可以用 Read10X()
读取多个样本,并用 merge()
或 IntegrateData()
进行合并。
Seurat:
# 读取多个样本数据
sample1 <- Read10X("path/to/sample1/filtered_feature_bc_matrix")
sample2 <- Read10X("path/to/sample1/filtered_feature_bc_matrix")
seurat_obj1 <- CreateSeuratObject(counts = sample1, project = "sample1")
seurat_obj2 <- CreateSeuratObject(counts = sample2, project = "sample1")
# 合并对象
seurat_obj <- merge(seurat_obj1, y = seurat_obj2, add.cell.ids = c("sample1", "sample1"))
在 Scanpy,可以使用 sc.read_10x_mtx()
逐个读取样本,并用 sc.concat()
进行合并。
Scanpy:
import scanpy as sc
import os
ssample_dirs = ["sample1", "sample2", "sample3", "sample4", "sample5", "sample6", "sample7", "sample8"]adatas = []
for sd in sample_dirs:
path = os.path.join("/data", sd, "filtered_feature_bc_matrix")
ad = sc.read_10x_mtx(path, var_names='gene_symbols')
ad.obs["sample"] = sd # 添加样本名
adatas.append(ad)
# 合并样本
adata = sc.concat(adatas, label='sample', keys=sample_dirs, index_unique='-')
✅ 对比: Seurat 使用
merge()
,而 Scanpy 推荐使用sc.concat()
进行样本合并。
2. 质量控制(QC)
Seurat:
seurat_obj <- subset(seurat_obj, subset = nFeature_RNA > 200 & nFeature_RNA < 6000 & percent.mt < 10)
Scanpy:
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)
adata.var['mt'] = adata.var_names.str.startswith('MT-')
adata.obs['percent_mt'] = (
adata[:, adata.var['mt']].X.sum(1) / adata.X.sum(1)
) * 100
adata = adata[adata.obs['percent_mt'] < 10, :]
✅ 对比: Seurat 的
subset()
直接筛选,而 Scanpy 需要手动计算线粒体基因比例。
3. 归一化与高变基因选择
Seurat:
seurat_obj <- NormalizeData(seurat_obj)
seurat_obj <- FindVariableFeatures(seurat_obj, selection.method="vst", nfeatures=2000)
Scanpy:
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, flavor='seurat_v3', batch_key='sample', n_top_genes=2000)
adata = adata[:, adata.var['highly_variable']]
✅ 对比: Seurat 使用
FindVariableFeatures()
,Scanpy 则使用sc.pp.highly_variable_genes()
进行变量基因筛选。
4. 去批次整合(Batch Correction)
在 Seurat 中,通常使用 IntegrateData()
进行批次校正。
Seurat:
seurat_obj <- FindIntegrationAnchors(object.list = list(seurat_obj1, seurat_obj2))
seurat_obj <- IntegrateData(anchorset = seurat_obj)
在 Scanpy,可以使用 BBKNN 进行批次校正。
Scanpy:
import scanpy.external as sce
sce.pp.bbknn(adata, batch_key='sample')
✅ 对比: Seurat 使用
IntegrateData()
,而 Scanpy 推荐使用 BBKNN 进行批次整合。
5. 确保分析结果可重复
在 Seurat,我们可以使用 set.seed()
以保证可复现性。
Seurat:
set.seed(42)
在 Scanpy,等效的方法是:
import numpy as np
import random
np.random.seed(42)
random.seed(42)
sc.settings.n_jobs = 1 # 限制多线程计算,以避免并行计算的随机性
此外,为了确保 UMAP 结果可重复,应在 sc.tl.umap()
中设置 random_state
。
sc.tl.umap(adata, min_dist=0.3, spread=1.0, random_state=42)
✅ 对比: Scanpy 需要设置
random_state=42
并使用np.random.seed(42)
以确保 UMAP 结果可重复。
6. 总结
本笔记对比了 Seurat 和 Scanpy 在多样本分析中的核心操作,涵盖 数据读入、批次整合、降维、UMAP 参数优化、可重复性控制 等内容。希望能帮助你在两者之间快速切换!