
如果你做生物信息学、单细胞转录组分析有一个场景一定不陌生拿到了表达矩阵准备开始跑 Seurat 或 Scanpy结果第一步环境就装了整整一个下午。更常见的情况是教程里的代码你在终端里复制粘贴跑完却看不到任何可视化结果因为聚类图根本没弹出来或者报了十几个版本冲突的错误。这篇文章想讨论的不只是“Jupyter Notebook 怎么用”也不是“Scanpy 的 API 有哪些”。我想回答一个更实际的问题如何把 Jupyter Notebook 和 Scanpy 组合起来搭出一套适合自己的单细胞分析工作台。我相信对多数做数据分析的人来说Jupyter Notebook 不只是一个写代码的网页工具它更是一种调试思维和可视化节奏的载体。而 Scanpy 代表的是 Python 生态里一整套单细胞分析范式。两者搭配能让你从读数据、质控、标准化、聚类到可视化全流程都在同一个界面里完成。这篇文章会按真实使用顺序展开。先讲 Jupyter Notebook 和 Jupyter Lab 怎么选、Anaconda 环境怎么装、Scanpy 怎么安装再讲 Jupyter Notebook 的常用操作和容易踩的坑然后进入 Scanpy 核心数据结构 AnnData最后给出一个完整可跑的 Scanpy 示例从 pbmc3k 测试数据开始到 UMAP 可视化和 marker 基因识别结束。每个阶段我都会给代码、给判断、给排查思路。你在阅读过程中可以顺手打开终端跟着操作。不要只看不跑这类工具文章最大的价值在于你把命令完整敲过一遍之后形成的手感和肌肉记忆。1. 为什么是 Jupyter Notebook 加 Scanpy先聊一个最基本的判断。很多人第一次接触单细胞分析会先在 R 语言里用 Seurat后来转到 Python 这边时会问我为什么要用 ScanpyJupyter Notebook 不就是个网页版的笔记本吗我的看法是Scanpy 的价值并不只是“又多了一个 Python 包”而在于它把单细胞分析流程结构化成了可复现、可扩展的 Pipeline。它的数据对象 AnnData 会把表达矩阵、细胞元信息、基因元信息和降维结果统一收纳。这种数据结构设计非常符合交互式分析的习惯你每一步操作都在往同一个对象上叠加结果不用频繁地维护多个 DataFrame也不用手动保存中间文件。而 Jupyter Notebook 恰好提供了这种交互式分析的最佳载体。它支持代码和 Markdown 混排你可以一边写分析逻辑一边记录思考可以分 Cell 运行把耗时步骤独立出来还可以在同一个页面里渲染 UMAP、热图、小提琴图。相比直接在终端里跑 Python 脚本Jupyter Notebook 更接近“分析过程的白板”你可以随时回退、修改、重新执行某个 Cell。需要注意一个边界Jupyter Notebook 并不是万能的。它适合探索性分析、流程原型验证和技术分享但如果你要做大规模自动化批量分析或者要部署到生产环境更合适的方式是把核心逻辑写成 Python 模块或脚本再配合流程管理工具执行。这个边界理解清楚了你才不会把 Jupyter Notebook 用成一把不合适的锤子。2. Jupyter Notebook 的核心概念与适用场景2.1 Notebook 是什么Jupyter Notebook 是一个基于 Web 的交互式计算环境核心单位是 Cell。一个 Cell 可以是一段 Python 代码也可以是 Markdown 文本。代码 Cell 可以单独执行并保留变量状态Markdown Cell 用来写说明和结论。Notebook 文件以.ipynb格式保存里面包含代码、输出、富文本展示和元数据。这种“代码 输出 文档”合一的格式特别适合做数据分析。因为它天然保留了执行顺序和结果你可以随时复盘某一列数据在哪个步骤被过滤了某个聚类结果是在什么参数下得到的图表对应的代码是哪一段。对单细胞分析这种步骤多、参数多的任务来说这种可追溯性非常重要。2.2 Jupyter Notebook 与 Jupyter Lab 的区别很多新手会纠结到底装哪个。这里给你一个明确的结论如果你二选一优先考虑 Jupyter Lab但不要因此忽略 Notebook。Jupyter Lab 是 Jupyter 项目的下一代界面它把 Notebook、终端、文件管理器、文本编辑器集成到了同一个界面中。简单说Jupyter Lab 是“集成开发环境”而 Jupyter Notebook 是“单文档笔记本”。如果你的工作流是单细胞分析你经常需要在笔记本、终端和图像窗口之间切换。Jupyter Lab 的多标签布局会更顺手。你可以左侧开一个 Notebook右侧跑一个终端上方还能拖一个图像窗口不用来回切浏览器标签。但如果你只是快速查看一个已有的 Notebook 文件或者只是想跑一个简短的分析流程Jupyter Notebook 的简洁界面依然够用。一个重要提醒是很多教程在讲“Jupyter Notebook 安装”时实际上默认安装的是 Jupyter Lab。这不是错误因为jupyter notebook命令在很多环境里依然可用。你需要知道自己用的到底是哪个界面否则在看菜单、找按钮时会觉得和教程对不上。2.3 Notebook 适合哪些场景单细胞数据的探索性分析读入数据、过滤、标准化、聚类、可视化。数据清洗和特征工程的流程原型。机器学习模型的快速试错和小样本训练。教学和分享代码、输出、图表和解释放在一起读者可以逐段理解。分析报告生成执行完成后可以导出为 HTML 或 PDF。注意Notebook 不适合作为生产调度的载体。如果你有每天自动跑的一次性分析任务应该把核心逻辑抽成.py脚本再用调度工具执行。Notebook 适合人机交互脚本适合无人值守。3. 环境准备与安装环境准备这一步是很多新手卡住的地方。我建议按照“Anaconda → 虚拟环境 → Jupyter → Scanpy”的顺序来不要直接在 base 环境里安装一堆包。3.1 安装 AnacondaAnaconda 是一个 Python 发行版自带 conda 包管理器和大量常用科学计算包。它解决了两个痛点Python 环境隔离和底层依赖管理。对生物信息学分析来说很多包依赖特定版本的 numpy、scipy直接用 pip 安装容易冲突conda 则能从通道层面处理这些依赖。安装方式比较简单可以去 Anaconda 官网下载对应系统的安装包。安装完成后打开终端检查conda --version python --version如果显示 conda 版本号和 Python 版本说明安装成功。这里提醒一下安装 Anaconda 的过程中安装器默认会执行conda init修改 shell 配置文件。如果你不想让 conda 自动激活 base 环境可以执行conda config --set auto_activate_base false这样每次打开终端不会自动进入 base 环境虚拟环境管理会更清爽。3.2 创建并激活虚拟环境强烈建议为单细胞分析单独建一个环境不要直接在 base 环境里安装 scanpy。原因是 scanpy 依赖的包版本很多和 base 环境里已有的包可能冲突。单独建环境可以让你随意升级、回滚不会搞坏其他项目。conda create -n scanpy_env python3.9 -y conda activate scanpy_env创建后你的终端提示符前面会出现(scanpy_env)说明当前处于该虚拟环境中。3.3 安装 Jupyter Notebook在虚拟环境中安装 Jupyterconda install jupyter -y这条命令会安装 Jupyter Notebook 和 Jupyter Lab。如果你只需要 Notebook也可以conda install notebook -y安装完成后在虚拟环境里启动jupyter notebook如果一切正常终端会输出一段以http://localhost:8888开头的 URL然后浏览器会自动打开 Notebook 界面。这里有个常见误区你在某个环境里安装了 jupyter但这个环境里的 jupyter 命令可能和你系统全局的 jupyter 不是同一个。如果在启动时报错找不到命令用下面命令确认是否在当前环境which jupyter在 scanpy_env 环境中应该显示该环境下的路径。3.4 安装 ScanpyScanpy 是一个基于 Python 的单细胞分析框架官方推荐通过 conda 或 pip 安装。在 scanpy_env 环境中执行conda install -c conda-forge scanpy -y也可以使用 pippip install scanpy两种方式都可行。conda-forge 渠道在依赖解析方面更严格pip 方式更直接。如果你同时使用 R 生态和 Python 生态并且后续可能在同一个环境里安装其他生物信息学工具conda 方式通常更省心。安装完成后验证python -c import scanpy as sc; print(sc.__version__)能输出版本号说明安装成功。注意不要纠结于具体版本号Scanpy 在不断更新本文示例基于主流稳定版本API 基本兼容。3.5 PyCharm 中的 Jupyter Notebook如果你习惯使用 PyCharm有两种方式启动 Jupyter Notebook。第一种在 PyCharm 的 Terminal 面板中运行jupyter notebook会在你当前项目目录下启动服务。此时 PyCharm 的 Terminal 和你操作系统终端的区别只是界面集成命令行为一致。第二种PyCharm Professional 版本支持直接打开.ipynb文件并在 Python 解释器中配置 Jupyter 服务器。如果你是 Community 版本没有直接打开 Notebook 的功能更推荐使用方式一或者直接使用 Jupyter Lab。需要留意的是PyCharm 中如果要用自定义 conda 环境需要在 Settings 里把 Python Interpreter 指向对应环境。否则你打开 Notebook 后创建的 Kernel 会使用错误环境导致 import scanpy 失败。4. Jupyter Notebook 基础操作与常用技巧4.1 新建 Notebook 与界面认识打开 Jupyter Notebook 后你会看到文件列表。点击右侧的 “New” 下拉菜单选择 “Python 3” 即可新建笔记本。界面顶部是菜单栏和工具按钮主要区域是 Cell。每个 Cell 都有一个输入框和输出区域。代码 Cell 写的 Python 代码执行后结果会直接显示在输出区域。Markdown Cell 显示渲染后的文本。新建 Notebook 后建议第一时间把文件保存为有意义的名字比如pbmc3k_scanpy_analysis.ipynb。这比默认的Untitled.ipynb好一万倍。4.2 核心快捷键Shift Enter运行当前 Cell 并移动到下一个 Cell。Ctrl Enter运行当前 Cell但不移动。A在当前 Cell 上方插入新 Cell。B在当前 Cell 下方插入新 Cell。D D连续按两次 D删除当前 Cell。M把当前 Cell 切换为 Markdown。Y把当前 Cell 切换为 Code。Esc退出编辑模式。Enter进入编辑模式。这些快捷键是日常使用最频繁的建议练习到肌肉记忆。4.3 魔法命令Jupyter Notebook 支持 IPython 的魔法命令它们以%开头用来简化操作。# 在 Notebook 中显示 matplotlib 图像 %matplotlib inline # 查看当前工作目录 %pwd # 列出当前目录文件 %ls # 运行一个 Python 脚本 %run myscript.py # 统计单行代码执行时间 %timeit sum(range(1000)) # 统计整个 Cell 执行时间 %%time import time time.sleep(1)其中%matplotlib inline在做单细胞可视化时非常重要。没有这行命令sc.pl.umap()产出的图在某些环境下可能不显示。不过要注意在 Jupyter Lab 中matplotlib 的渲染方式已经优化有时不设置 inline 也能正常显示。但这行命令在 Notebook 中依然是稳妥选择。4.4 Markdown 基本写法Markdown Cell 支持标题、列表、链接、图片和 LaTeX 公式。写分析报告时建议每个分析阶段都加一个 Markdown Cell说明这一个步骤的目标和判断依据。### 数据质控 本步骤过滤掉低质量细胞和低表达基因。 - 每个细胞至少表达 200 个基因 - 每个基因至少在 3 个细胞中表达4.5 如何在其他浏览器中打开 Jupyter Notebook默认情况下Jupyter Notebook 会用系统默认浏览器打开。如果你想在指定浏览器中打开有几种方式。方式一启动时使用--no-browser不自动打开浏览器然后手动复制 URL 到你想要的浏览器。jupyter notebook --no-browser启动后终端会显示类似http://localhost:8888/?tokenxxxxxxxx的 URL你复制到 Chrome 或 Edge 中即可。方式二修改 Jupyter 配置文件的浏览器设置。jupyter notebook --generate-config这会生成~/.jupyter/jupyter_notebook_config.py打开文件找到c.NotebookApp.browser配置项取消注释并设置为你想要的浏览器启动命令。c.NotebookApp.browser rC:\Program Files\Google\Chrome\Application\chrome.exe --new-window %s注意Windows 路径中需要写成双反斜杠。设置完成后重启 Jupyter Notebook 即可生效。方式三如果你在服务器或远程主机上运行 Jupyter需要把127.0.0.1:8888做端口转发。这里是合法运维场景下的常规操作建议结合公司或云平台的网络策略实施。如果你只是为了本地分析用方式一就够了。5. Windows 下 Jupyter Notebook 打开后空白的排查思路之前的热搜词里有一个很典型的问题Windows 下 Jupyter Notebook 打开后空白。这个问题在网络搜索中的出现频率非常高很多人在安装 Anaconda 后双击打开 Jupyter Notebook浏览器里却只有一个空白页。这里先说结论空白页面大多数情况下不是 Jupyter 本身坏了而是浏览器端脚本加载或显示异常。排查顺序建议如下。第一步看终端输出。Jupyter 在启动时会在终端实时输出日志。如果终端里显示http://localhost:8888且没有任何报错说明服务端正常。如果终端有红色报错先看报错信息。第二步检查浏览器地址栏。如果地址是http://localhost:8888或http://localhost:8888/tree但页面空白先尝试强制刷新页面快捷键是Ctrl Shift R。有时候是浏览器缓存了旧的脚本导致新版本加载失败。第三步换一个浏览器。曾经有用户反馈某些安全策略严格的浏览器扩展会导致 Jupyter 页面空白。换成 Chrome 无痕模式或 Edge 试试。第四步检查环境。Jupyter 的依赖包版本如果出现冲突也可能导致前端资源加载失败。此时可以在当前环境执行pip install --upgrade notebook如果你用的是 conda也可以conda update notebook -y第五步如果还是空白考虑端口冲突或防火墙策略。8888端口如果被其他程序占用Jupyter 会自动切换端口在终端会看到http://localhost:8889之类的地址。确认你访问的是终端中显示的最新地址。从排查经验来看大多数空白问题集中在浏览器缓存和扩展插件上。不建议第一反应就重装 Anaconda那会把问题扩大化。6. Scanpy 的核心数据结构AnnData在写 Scanpy 代码之前必须先理解 AnnData。它是 Scanpy 的数据容器也是整个分析流程的“中枢”。AnnData 有几个关键属性X表达矩阵通常是一个numpy.ndarray或scipy.sparse矩阵。行是细胞列是基因值表示表达量。obs细胞维度的元数据。每个细胞所属的样本、批次、测序深度、线粒体基因比例等信息都存在这里。var基因维度的元数据。基因名、基因类型、高变基因标记等信息存在这里。obsm细胞维度的降维结果比如 PCA、UMAP、TSNE 的结果。varm基因维度的降维结果。uns自由存放分析过程中产生的非结构化信息比如聚类颜色的映射、marker 基因结果。layers表达矩阵的多层表示比如原始计数、标准化后的值、log 转换后的值。用一个通俗的类比来理解AnnData 像一个 Excel 工作簿。X是主表obs是每个样本行的备注列var是每个基因列的备注行obsm是额外添加的“分析结果 Sheet”。一次 Scanpy 分析的本质就是不断在 AnnData 上做操作然后把结果写回对应属性。因此你在分析时要养成习惯每执行一个分析步骤用print(adata)查看 AnnData 对象的变化。它会显示细胞数、基因数以及已经被添加的 key 名称。这比记忆 API 更有效。7. Scanpy 完整分析流程从 pbmc3k 到 UMAP 与 marker 基因这一节我们用一个公开测试数据集pbmc3k来走通全流程。这个数据集来自 10X Genomics包含 2700 个外周血单核细胞数据量小适合教学演示。7.1 加载数据在 Jupyter Notebook 中新建一个 Cell输入以下代码并执行import scanpy as sc # 设置图像显示优化svg 格式放大不模糊 sc.settings.set_figure_params(dpi100, facecolorwhite) adata sc.datasets.pbmc3k() print(adata)执行后你会看到 AnnData 对象的概要信息包括细胞数和基因数。pbmc3k()函数会从 Scanpy 的示例数据源下载数据。如果网络受限也可以把数据文件放到本地后用sc.read_10x_mtx()读取我们稍后会讲。7.2 数据质控质控的目的是去掉“空液滴”和“多细胞液滴”。常用的标准是每个细胞检测到的基因数、测序深度和线粒体基因比例。import pandas as pd import numpy as np # 过滤低质量细胞至少表达 200 个基因 sc.pp.filter_cells(adata, min_genes200) # 过滤低表达基因至少在 3 个细胞中表达 sc.pp.filter_genes(adata, min_cells3) # 计算线粒体基因比例 adata.var[mt] adata.var_names.str.startswith(MT-) sc.pp.calculate_qc_metrics( adata, qc_vars[mt], percent_topNone, log1pFalse, inplaceTrue ) # 过滤线粒体比例过高和基因数过多的细胞 sc.pp.filter_cells(adata, max_genes5000) adata adata[adata.obs.pct_counts_mt 20, :].copy() print(f质控后剩余细胞数: {adata.n_obs})这里adata.var[mt]是一个布尔向量标记哪些基因是线粒体基因。注意不同数据库中线粒体基因前缀不一样人类是MT-小鼠是mt-如果分析小鼠数据需要相应调整。质控的逻辑并不复杂但参数选择会影响后续分析结果。max_genes5000和pct_counts_mt 20是常用的经验值具体项目中应该结合数据的实际分布来调整。最好在质控前先画出分布图再确定阈值。7.3 标准化与高变基因单细胞测序数据存在测序深度差异需要标准化来消除这种技术因素。# 总量标准化每个细胞的总表达量归一化到 10000 sc.pp.normalize_total(adata, target_sum1e4) # 对数转换 sc.pp.log1p(adata)标准化之后识别高变基因。这些基因在细胞间表达差异最大用来做主成分分析更能代表细胞类型。sc.pp.highly_variable_genes(adata, min_mean0.0125, max_mean3, min_disp0.5) print(adata.var.head())可视化高变基因的分布sc.pl.highly_variable_genes(adata)这一步会输出高变基因筛选图横轴是平均表达量纵轴是离散度。全流程中你可以看到两张图这比干看代码直观得多。7.4 PCA 降维在做 PCA 之前通常先把数据限定到高变基因并且保存一份标准化后的完整数据到raw方便后续 marker 基因可视化时参考。# 保存标准化后的完整数据 adata.raw adata # 下一步分析用高变基因 adata adata[:, adata.var.highly_variable] # PCA sc.tl.pca(adata, svd_solverarpack) sc.pl.pca_variance_ratio(adata, n_pcs50)sc.pl.pca_variance_ratio会画出方差解释率曲线用来决定后续邻居图使用多少个主成分。根据曲线拐点通常选择 10 到 40 个主成分。7.5 邻居图与 UMAPPCA 之后我们用主成分空间构建细胞之间的邻居关系这是聚类和可视化共同的基础。sc.pp.neighbors(adata, n_neighbors10, n_pcs40) sc.tl.umap(adata) sc.pl.umap(adata, colorleiden)这里会运行 UMAP 算法。UMAP 的随机性比较强如果想让结果可复现可以设置random_statesc.tl.umap(adata, random_state42)在 Notebook 中执行 UMAP 后adata.obsm[X_umap]会被写入这就是每个细胞的二维坐标。你可以用df pd.DataFrame(adata.obsm[X_umap], indexadata.obs_names)查看。7.6 聚类Scanpy 默认推荐使用 Leiden 算法进行聚类。Leiden 的核心参数是resolution它控制聚类的“粗粒度”和“细粒度”。数值越大得到的簇越多。sc.tl.leiden(adata, resolution0.5, random_state42)执行后聚类结果会写入adata.obs[leiden]。重新绘制 UMAP颜色按聚类着色sc.pl.umap(adata, color[leiden], legend_locon data)legend_locon data会把簇标签显示在对应聚类区上方便直接观察。7.7 识别 marker 基因聚类之后最重要的一个任务是找出每个 cluster 的 marker 基因。Scanpy 使用rank_genes_groups做差异表达分析。sc.tl.rank_genes_groups(adata, leiden, methodwilcoxon, n_genes20)查看结果result adata.uns[rank_genes_groups] for cluster in result[names].dtype.names: genes list(result[names][cluster][:10]) print(fCluster {cluster}: {genes})也可以用 Scanpy 内置的可视化函数绘制 marker 基因热图sc.pl.rank_genes_groups_heatmap(adata, n_genes10, groupbyleiden)这张热图非常直观每一列是 cluster每一行是 marker 基因。颜色越亮代表该基因在这个 cluster 中表达越高。7.8 保存与导出分析完成后建议保存为.h5ad文件这是 Scanpy 的标准格式可以保留全部分析结果。adata.write(pbmc3k_analysis.h5ad)同时可以导出 UMAP 坐标和 marker 基因表格方便后续用其他工具查看。umap_df pd.DataFrame( adata.obsm[X_umap], indexadata.obs_names, columns[UMAP1, UMAP2] ) umap_df[leiden] adata.obs[leiden].values umap_df.to_csv(pbmc3k_umap.csv)8. 如何读取本地 10X 数据scanpy.datasets.pbmc3k()适合学习演示但在真实项目中你面对的是filtered_feature_bc_matrix文件夹或.h5文件。Scanpy 提供了对应接口。如果数据是 10X 的.h5格式adata sc.read_10x_h5(filtered_feature_bc_matrix.h5) # 注意如果数据来自多个样本通常需要先合并再做分析 adata.var_names_make_unique()如果数据是 10X 的 mtx 格式文件夹中包含barcodes.tsv.gz、genes.tsv.gz、matrix.mtx.gzadata sc.read_10x_mtx( filtered_feature_bc_matrix/, var_namesgene_symbols, make_uniqueTrue )var_namesgene_symbols表示使用基因符号作为基因名而不是 Ensembl ID。读取后建议先打印adata和print(adata.var.head())确认基因名正确。如果你有多个样本需要合并。Scanpy 支持用concat合并import scanpy as sc import anndata as ad adata_list [] for sample in [sample1, sample2]: adata_tmp sc.read_10x_h5(f{sample}/filtered_feature_bc_matrix.h5) adata_tmp.obs[sample] sample adata_list.append(adata_tmp) adata ad.concat(adata_list, joinouter, labelbatch) adata.var_names_make_unique()合并后别忘了做批次整合。批次效应是单细胞分析的大坑如果不同样本存在明显批次差异聚类结果可能被批次主导而不是生物差异。常用策略包括 Harmony、BBKNN 或 Scanorama。Scanpy 生态中Harmony 可以通过sc.external.pp.harmony_integrate调用不过需要额外安装。9. 常见问题与快速排查问题现象可能原因排查方式解决方案Jupyter Notebook 启动后浏览器空白浏览器缓存或扩展插件冲突notebook 前端资源加载失败强制刷新换浏览器无痕模式查看终端日志升级 notebook更换浏览器清理缓存端口 8888 被占用已经有一个 Jupyter 服务在运行查看终端日志中的新端口访问终端提示的新 URL或关闭旧进程import scanpy报错 ModuleNotFoundError当前 Kernel 环境不是安装 scanpy 的环境执行which python检查 Jupyter Kernel 列表把 Jupyter 的 Kernel 指向正确环境或在正确环境重新安装 jupytersc.read_10x_h5读取后基因名为 Ensembl ID没有使用var_names参数查看adata.var.head()用var_namesgene_symbols重新读取UMAP 结果每次运行都不一样UMAP 和 Leidan 有随机性没有设置随机种子设置random_state参数质控后细胞数过多或过少过滤阈值不合理绘制分布图判断拐点调整min_genes、max_genes、pct_counts_mt聚类个数太多或太少resolution 参数不合适尝试多个 resolution 值调小/调大 resolution通常范围在 0.1 到 2.0 之间这里要特别强调一个容易忽略的问题Kernel 环境不一致。你可以在终端用pip install scanpy安装成功但 Jupyter Notebook 使用的 Kernel 可能是另一个 Python 环境。打开 Notebook 后在代码 Cell 里执行import sys; print(sys.executable)输出的路径应该是安装 scanpy 的虚拟环境路径。如果不是说明 Kernel 配置错了。修复方式是在正确环境中安装 ipykernel并添加内核conda activate scanpy_env pip install ipykernel python -m ipykernel install --user --name scanpy_env --display-name Python (scanpy_env)然后刷新 Jupyter Notebook 页面在 Kernel 菜单里切换为 “Python (scanpy_env)”。10. 最佳实践与工程建议10.1 用 Markdown Cell 记录分析日志单细胞分析是强探索性的工作你会反复调整阈值和参数。建议在每个步骤之前用 Markdown Cell 说明当前分析的版本、数据和目标在步骤之后记录结论。这不仅是给别人看的更是给你自己看的。两周之后再打开 Notebook你会庆幸当时记录了“为什么要把min_genes设为 200”。10.2 保存中间结果单细胞数据分析流程较长有些步骤比如聚类和 marker 基因分析耗时久。建议在关键节点保存.h5ad文件。不过要注意.h5ad文件会包含全部原始数据体积较大只适合作为中间结果保留。你需要理解并遵守当前实验室或分析环境关于数据存储和敏感数据的合规要求不要随意把数据复制到未授权位置。10.3 生产环境不要用 Notebook 跑全流程Notebook 适合交互式探索但正式批量跑数据时建议把核心分析流程写成.py脚本通过命令行参数传递输入输出路径。这样更利于日志记录、异常处理和定时调度。你可以把 Notebook 当作“开发草稿”把脚本当作“正式交付物”。10.4 理解数据而不是盲目套参数很多新手在质控时直接把阈值抄过来min_genes200、max_genes5000、pct_counts_mt 20。这些参数对 pbmc3k 有效但换到肿瘤数据、空间转录组数据、不同测序平台的数据时可能需要完全不同的阈值。我强烈建议每次过滤前都画出基因数、测序深度、线粒体比例的分布图用数据说话。10.5 多环境管理在 conda 里为不同项目建不同环境是一个好习惯。比如scanpy_env专门做单细胞分析ml_env专门做机器学习。多用conda env list查看环境用conda env export environment.yml导出环境依赖。这样换机器、换同事电脑时几行命令就能恢复环境。10.6 版本记录在分析报告的末尾加上一行版本信息import scanpy as sc import anndata as ad print(fscanpy: {sc.__version__}) print(fanndata: {ad.__version__})不要小看这行代码。几个月后如果结果需要复现它是最直接的线索。11. 总结与后续学习方向这篇文章从 Jupyter Notebook 的安装和基础操作讲起重点放在它与 Scanpy 组合使用时的完整工作流。你应该已经理解Jupyter Notebook 是一种交互式分析载体扫描分析的核心是理解 AnnData 的数据结构而不是死记 APIScanpy 的标准流程是数据加载、质控、标准化、高变基因选择、PCA、邻居图、UMAP、Leiden 聚类和 marker 基因分析。如果你完整跑通了上面的 pbmc3k 示例接下来可以沿着四个方向深入第一换一份真实数据练习。到 10X Genomics 官网下载公开数据集或者使用你的研究组数据把 pbmc3k 的流程重新跑一遍。真实数据永远比教程数据复杂你会遇到批次效应、稀疏矩阵、不同样本合并等问题。第二深入学习标注。Leiden 聚类得到的数字编号并没有生物学含义你需要对照 marker 基因把它们标注成 T 细胞、B 细胞、NK 细胞等这需要一定免疫学知识。后面我也计划专门写一篇基于 P 细胞类型自动注释的方法对比。第三学习批量整合。Harmony、BBKNN、Scanorama 这些工具解决的是同样问题不同样本之间的批次效应。它们各有适用条件理解它们的数学假设比会用 API 更重要。第四把工作流工程化。把 Notebook 迁移成.py脚本学习 Snakemake 或 Nextflow 这类流程管理工具能把你的分析从“自己跑通”提升到“可重复、可共享、可规模部署”。最后提醒一句单细胞分析的上限不在工具而在实验设计和你对生物学问题的理解。Jupyter Notebook 和 Scanpy 能帮你把分析过程整理得井井有条但一个清晰的研究问题才是整个分析流程真正的起跑线。