scvi-tools 数据准备完整指南:从原始计数到可训练 AnnData 的标准化流程

发布时间:2026/9/12 3:43:15
scvi-tools 数据准备完整指南:从原始计数到可训练 AnnData 的标准化流程
scvi-tools 数据准备完整指南从原始计数到可训练 AnnData 的标准化流程【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins本指南系统讲解在 scvi-toolsscVI/scANVI/totalVI/MultiVI 等深度生成模型中如何正确准备 AnnData 对象覆盖原始计数校验、QC 过滤、counts 层存储、高变基因HVG选择、setup_anndata()注册以及多模态数据的特殊处理。本文源自 data_preparation.md并结合本仓库 scvi-tools 技能包中的 model_utils.py、prepare_data.py 与 validate_adata.py 源码进行纵深展开读完可直接上手一套可复现、可验证的预处理流水线。Overview为什么数据准备决定 scvi-tools 成败scvi-tools 的模型是概率深度生成模型变分自编码器 VAE 家族其训练目标是从原始计数矩阵中学习负二项Negative Binomial等计数分布的参数。因此数据准备有三个硬性要求原始计数Raw counts输入必须是整数计数而非 log-normalized、CLR 等变换后的浮点数据否则模型假设的计数似然不再成立高变基因选择HVG将特征从数万个基因裁剪到 1500–5000 个信息量最大的基因既降低内存与计算开销又提升训练稳定性正确的setup_anndata()调用通过注册接口把 counts 层、批次信息、标签、协变量等元数据告知模型这是模型构建的前置步骤。三者缺一不可。仓库中的 SKILL.md 也在 Critical Requirements 一节中明确强调scvi-tools 模型需要整数计数数据、2000–4000 个 HVG、以及batch_key的显式指定。为便于一键落地仓库提供了scripts/prepare_data.py命令行与scripts/model_utils.py中的prepare_adata()Python API两套实现本文会与手写步骤一一对照。Step 1: 加载与检查数据——先确认 X 里到底是什么scvi-tools 的输入校验是宽进严出的如果直接拿归一化数据训练通常会在后续报出 X should contain integers 之类的错误。因此在任何预处理之前先加载数据并确认adata.X的形态import scanpy as sc import scvi import numpy as np # Load data adata sc.read_h5ad(data.h5ad) # Check whats in adata.X print(fShape: {adata.shape}) print(fX dtype: {adata.X.dtype}) print(fX contains integers: {np.allclose(adata.X.data, adata.X.data.astype(int))}) print(fX min: {adata.X.min()}, max: {adata.X.max()})从.raw或layers找回原始计数如果X已经被归一化比如直接读入了 Scanpy 标准流程的输出通常原始计数还保存在两个位置之一# scvi-tools needs INTEGER counts # If X appears normalized, check for raw counts if hasattr(adata, raw) and adata.raw is not None: print(Found adata.raw) # Use raw counts adata adata.raw.to_adata() # Or check layers if counts in adata.layers: print(Found counts layer) # Will specify layer in setup_anndataadata.raw是 Scanpy 的只读原始数据快照adata.raw.to_adata()会返回以原始计数为X的新的 AnnDataadata.layers[counts]则是用户自行保存的层。仓库中的 validate_adata.py 提供了与上面手写检查等价的自动化版本validate_for_scvi()会检查矩阵是否为整数np.allclose(X, X.astype(int))、是否含负值、是否含 NaN/Inf、以及值的量级max_val 10时给出可能已被 log 或归一化的警告。在命令行中可一键运行python bio-research/skills/scvi-tools/scripts/validate_adata.py raw.h5ad --batch-key batch --suggest其中--suggest会根据数据形态是否检测到protein_expression、spliced/unspliced层、特征数量、标签与批次列自动推荐模型类型——这正是把数据检查与选模型串联起来的高效做法。Step 2: 基础 QC 过滤——细胞与基因双重筛选确认是原始计数后进行标准的 QC 过滤。核心逻辑是过滤掉检测基因数过少/过多的细胞前者是空滴或低质量细胞后者可能是双细胞过滤掉线粒体基因占比过高的细胞凋亡细胞信号再过滤掉在极少数细胞中表达的基因# Filter cells (standard QC) sc.pp.filter_cells(adata, min_genes200) sc.pp.filter_cells(adata, max_genes5000) # Calculate mito percent if not present # Handle both human (MT-) and mouse (mt-, Mt-) mitochondrial genes adata.var[mt] ( adata.var_names.str.startswith(MT-) | adata.var_names.str.startswith(mt-) | adata.var_names.str.startswith(Mt-) ) sc.pp.calculate_qc_metrics(adata, qc_vars[mt], inplaceTrue) adata adata[adata.obs[pct_counts_mt] 20].copy() # Filter genes sc.pp.filter_genes(adata, min_cells3) print(fAfter filtering: {adata.shape})值得注意的是线粒体基因前缀的物种差异人类是MT-如MT-CO1小鼠则有mt-与Mt-两种大小写变体如mt-Co1、Mt-Nd1。仓库在 model_utils.py 中将这一逻辑封装为get_mito_genes()函数三组前缀取并集直接复用于后续的prepare_adata()。从源码看prepare_adata()的默认过滤参数与上面手写版本完全对齐参数默认值语义min_genes200每细胞最少基因数n_genes_by_counts min_genesmax_genes5000每细胞最多基因数max_mito_pct20.0线粒体基因占比上限严格而非min_cells3每个基因最少表达细胞数对应实现见 model_utils.py先sc.pp.calculate_qc_metrics(adata, qc_vars[mt], inplaceTrue)随后用n_genes_by_counts与pct_counts_mt三个布尔掩码切片过滤。Step 3: 保存原始计数到层——任何归一化之前的关键动作这一条是 scvi-tools 数据准备中最容易被忽略、代价最高的步骤一旦执行了normalize_totallog1pX中就不再是整数计数。所以必须先把原始计数备份到layers# Store raw counts in a layer adata.layers[counts] adata.X.copy() # Now you can normalize for other purposes (HVG selection) # But scvi will use the counts layer后续所有依赖归一化的操作如 HVG 选择的seuratflavor都在备份完成之后进行而 scvi-tools 模型在setup_anndata()中通过layercounts读取原始计数。仓库的两套实现都严格执行了先存层的顺序prepare_adata()在 model_utils.py 中adata.layers[counts] adata.X.copy()prepare_data.py 中同样如此。这也与 scrna_integration.md、citeseq_totalvi.md 等其他参考文档的约定一致——整个技能包统一约定层名为counts。Step 4: 高变基因选择——单批次与多批次两种策略scvi-tools 在 1500–5000 个 HVG 上效果最佳太少会丢失生物信号太多则引入噪声并显著放大内存/训练开销validate_adata.py 在 HVG 数量 1000 或 5000 时都会给出警告。单批次数据先归一化再选 HVGseuratflavor 依赖已归一化log 的数据因此先在副本上归一化选出 HVG 后再把标记传回原对象# Normalize for HVG selection only adata_hvg adata.copy() sc.pp.normalize_total(adata_hvg, target_sum1e4) sc.pp.log1p(adata_hvg) # Select HVGs sc.pp.highly_variable_genes( adata_hvg, n_top_genes2000, flavorseurat # or cell_ranger ) # Transfer HVG annotation adata.var[highly_variable] adata_hvg.var[highly_variable]多批次数据推荐seurat_v3 batch_key counts 层对于跨样本/跨平台整合场景推荐seurat_v3flavor。它直接在原始计数上计算均值-方差关系无需归一化配合batch_key时每个批次分别评估基因变异性再汇总从而选出跨批次一致可变的基因而不是被某个批次主导的基因# Use seurat_v3 flavor with batch_key # This selects genes variable across batches sc.pp.highly_variable_genes( adata, n_top_genes2000, flavorseurat_v3, batch_keybatch, # Your batch column layercounts # Use raw counts )仓库中的prepare_adata()把这两种策略封装为自动分支见 model_utils.py当提供了batch_key且该列存在于obs时走seurat_v3layercounts路径否则退回到归一化 → log1p →sc.pp.highly_variable_genes()→把X恢复为 counts 层内容的路径adata.X adata.layers[counts].copy()确保X仍是原始计数。这一恢复动作尤其值得注意它是为了选 HVG 临时归一化、选完必须还原的工程化保障。子集化到 HVG无论哪种 flavor最终都要裁掉非 HVG 基因# Subset to highly variable genes adata adata[:, adata.var[highly_variable]].copy() print(fAfter HVG selection: {adata.shape})从源码看prepare_adata()在子集化前用adata.var[highly_variable].sum()统计实际选中的 HVG 数并打印方便核对是否达到预期model_utils.py。validate_for_scvi()也会把n_hvg写入报告信息作为质量检查项。Step 5:setup_anndata()——把数据注册给模型setup_anndata()是 scvi-tools 1.x 的核心 API负责把数据矩阵与元数据注册为模型可消费的张量登记表。每个模型必须先用自身的setup_anndata()注册之后才能实例化模型。这一点与 0.x 时代scvi.data.setup_anndata()全局注册有本质区别详见 environment_setup.md 中的 API 迁移对照。基础注册scvi.model.SCVI.setup_anndata( adata, layercounts # Specify layer with raw counts )携带批次信息整合/批次校正必填scvi.model.SCVI.setup_anndata( adata, layercounts, batch_keybatch # Column in adata.obs )batch_key对应adata.obs中的一列如样本名、实验批次、测序平台scVI 会据此学习批次特异参数并在潜空间中抹平批次效应。从源码角度train_scvi()在 model_utils.py 中固定以layercounts 可选的batch_key调用SCVI.setup_anndata()而 validate_adata.py 还会额外检查批次列是否存在、批次数量是否只有 1 个提示可能无需校正、是否存在 50 个细胞的过小批次提示合并。携带细胞类型标签scANVI 半监督必需scvi.model.SCANVI.setup_anndata( adata, layercounts, batch_keybatch, labels_keycell_type # Column with cell type labels )scANVI 利用标签增强生物信号保留部分细胞无标签时可标记为Unknown参见 scrna_integration.md。train_scvi()中对应的流程是先训练 scVI再用SCANVI.from_scvi_model(scvi_model, labels_keylabels_key, unlabeled_categoryUnknown)初始化并微调model_utils.py。连续协变量scvi.model.SCVI.setup_anndata( adata, layercounts, batch_keybatch, continuous_covariate_keys[percent_mito, n_genes] )分类协变量scvi.model.SCVI.setup_anndata( adata, layercounts, batch_keybatch, categorical_covariate_keys[donor, technology] )连续协变量如线粒体占比、基因数与分类协变量如供体、技术平台用于在建模时显式剥离这些技术/生物混杂因素防止其污染潜空间。注意batch_key本质上是分类协变量的特殊形式多个分类协变量的写法见 scrna_integration.md 中的 Advanced: Multiple Categorical Covariates。各模型注册接口一览模型注册接口关键参数scVISCVI.setup_anndata()layer,batch_keyscANVISCANVI.setup_anndata()layer,batch_key,labels_keytotalVITOTALVI.setup_anndata()layer,protein_expression_obsm_key,batch_keyMultiVIMULTIVI.setup_mudata()rna_layer,atac_layer,batch_key,modalitiesPeakVIPEAKVI.setup_anndata()batch_keyveloVIVELOVI.setup_anndata()spliced_layer,unspliced_layer完整对照可参考 environment_setup.md。多模态数据注册totalVI 与 MultiVI当数据不止一个模态时注册方式随之扩展。CITE-seqRNA 蛋白totalVItotalVI 要求蛋白计数存放在adata.obsm[protein_expression]numpy 数组或稠密矩阵并在setup_anndata()中用protein_expression_obsm_key指向它# Protein data in adata.obsm # RNA in adata.X, protein in separate matrix # Add protein data adata.obsm[protein_expression] protein_counts # numpy array # Setup for totalVI scvi.model.TOTALVI.setup_anndata( adata, layercounts, batch_keybatch, protein_expression_obsm_keyprotein_expression )两个关键约束详见 citeseq_totalvi.md蛋白必须是原始 ADT 计数切勿使用 Seurat CLR 归一化结果蛋白不参与 HVG 过滤totalVI 会使用全部蛋白。此外建议把蛋白名存入adata.uns[protein_names]以便后续可视化与差异分析定位。MultiomeRNA ATACMultiVIMultiVI 推荐使用 MuData 组织两个模态并通过setup_mudata()注册# RNA and ATAC in separate AnnData objects or MuData import mudata as md # If using MuData mdata md.read(multiome.h5mu) scvi.model.MULTIVI.setup_mudata( mdata, rna_layercounts, protein_layerNone, batch_keybatch, modalities{rna: rna, accessibility: atac} )MuData 内部结构为mdata.mod[rna]与mdata.mod[atac]两个 AnnData。ATAC 侧预处理通常需要按min_cells10过滤峰、将可及性二值化为 0/1(X 0).astype(np.float32)、峰数量过多时按可及性排序截取前 50000 个multiome_multivi.md。注意实际项目源码与文档在modalities参数写法上略有出入文档示例为{rna: rna, accessibility: atac}的简写形式仓库 data_preparation.md 即采用此写法使用时以所装 scvi-tools 版本要求为准。一键流水线prepare_adata()与命令行prepare_data.py手写五步略显繁琐仓库为此提供了封装好的现成实现。Python API 方式from model_utils import prepare_adata # Prepare data with QC, HVG selection, and layer setup adata prepare_adata( adata, batch_keybatch, n_top_genes2000, min_genes200, max_mito_pct20 ) # Then setup for your model import scvi scvi.model.SCVI.setup_anndata(adata, layercounts, batch_keybatch)该函数model_utils.py一站式完成线粒体 QC 过滤复用get_mito_genes()兼容人类/小鼠前缀细胞与基因过滤n_genes_by_counts上下界 pct_counts_mt阈值 min_cells把原始计数存入layers[counts]HVG 选择提供batch_key时自动切换为批次感知的seurat_v3模式否则归一化选完 HVG 后恢复X为原始计数子集化到 HVG。命令行方式prepare_data.py则适合在 shell 中直接接入流水线# 基础准备 python bio-research/skills/scvi-tools/scripts/prepare_data.py raw.h5ad prepared.h5ad # 批次感知的 HVG 选择 python bio-research/skills/scvi-tools/scripts/prepare_data.py raw.h5ad prepared.h5ad --batch-key sample # 自定义参数 python bio-research/skills/scvi-tools/scripts/prepare_data.py raw.h5ad prepared.h5ad --n-hvgs 3000 --max-mito 15 # 数据已 QC 过跳过过滤 python bio-research/skills/scvi-tools/scripts/prepare_data.py filtered.h5ad prepared.h5ad --no-filter命令行参数与prepare_adata()一一对应--n-hvgs默认 2000、--min-genes200、--max-genes5000、--max-mito20.0、--min-cells3、--no-filter跳过 QC 过滤。脚本在main()中负责sc.read_h5ad()读入 →prepare_data()处理 →adata.write_h5ad()落盘并在每个阶段打印细胞/基因数变化如Filtered cells: 12000 → 10345便于核对流水线行为。检查注册结果view_anndata_setup()与注册元数据训练前建议确认数据已正确注册。注册信息会写入adata.uns的两个键中# View registered data print(adata.uns[_scvi_manager_uuid]) print(adata.uns[_scvi_adata_minify_type]) # For scVI scvi.model.SCVI.view_anndata_setup(adata)_scvi_manager_uuid记录注册管理器实例的标识_scvi_adata_minify_type记录数据精简minify类型而view_anndata_setup()会以结构化方式打印当前注册的层、批次、标签、协变量等全部登记信息——这是排查注册参数与预期不符的最直接手段。这也是 1.x 取代旧版scvi.data.view_anndata_setup()的对应新 API见 environment_setup.md。常见问题与解决方案原文档整理了一张排错表这里补充validate_for_scvi()源码中的具体判定逻辑方便对照问题原因解决方案X should contain integersX中存放的是归一化数据使用layercounts指向原始计数层batch_key not found列名拼写错误检查adata.obs.columns确认列名完全一致稀疏矩阵报错数据格式与算子不兼容转换为稠密矩阵adata.X adata.X.toarray()内存不足OOM特征数过多先子集化到 HVG2000–4000再训练数据含 NaN存在缺失值过滤或插补validate_for_scvi()会将 NaN/Inf 判为硬性错误除此之外validate_for_scvi()还会自动给出两类软性警告数据最大值为个位数疑似 log 变换n_obs 1000深度模型通常需要 5000 细胞以及建议X未归一化且无counts层时提示先备份原始计数存在adata.raw时提示用adata.raw.to_adata()恢复validate_adata.py。更全面的训练期问题训练发散、NaN loss、批次不混合等可参阅 troubleshooting.md。数据格式速查必需adata.X或adata.layers[counts]原始整数计数支持稀疏矩阵adata.obs细胞元数据 DataFrameadata.var基因元数据 DataFrame推荐adata.obs[batch]批次/样本标识列adata.var[highly_variable]HVG 布尔掩码scANVI 额外要求adata.obs[labels]细胞类型注释列允许包含Unknown表示未标注细胞小结一份可照抄的准备清单sc.read_h5ad()加载后用validate_adata.py或手工整数检查确认X是整数计数不是则从adata.raw/counts层恢复执行细胞min_genes/max_genes/pct_counts_mt与基因min_cells过滤线粒体前缀按人类MT-、小鼠mt-/Mt-一并处理在任何归一化前执行adata.layers[counts] adata.X.copy()按单批次seurat需临时归一化或多批次seurat_v3batch_keylayercounts完成 HVG 选择并子集化按模型调用对应的setup_anndata()/setup_mudata()正确传递layer、batch_key、labels_key、protein_expression_obsm_key、协变量等参数用view_anndata_setup()复核注册结果后再进入 train_model.py 等训练环节。上述任意步骤都可以替换为仓库现成工具prepare_data.py命令行 /prepare_adata()Python API既保证与 scvi-tools 官方语义一致又让流程可复现、可审计。整个技能包的模型选型与后续分析流程整合、标签迁移、多模态、空间反卷积等均以本文的counts 层 HVG setup约定为共同起点详见 SKILL.md 的 Workflow Reference Files 表格。【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考