BioF3 组学数据分析
基础入门手册
BioF3 基础入门专题导出版
导出日期:2026年6月27日
01 组学数据分析入门
如果是第一次接触生物信息学,这篇文章帮你建立一个清晰的认知框架:组学数据为什么需要专门的分析方法、它的整体流程长什么样、第一步该走到哪里。
从一份数据开始
假设手上有一份单细胞 RNA 测序数据:10000 个细胞 × 20000 个基因的表达矩阵,2 亿个数据点。
要回答的问题可能是:
- 这些细胞分成几种类型?
- 不同细胞类型的标志基因是什么?
- 细胞之间如何相互作用?
- 某个基因在哪些细胞中高表达?
组学分析的核心问题就在这一刻浮现:怎么从这份海量、嘈杂、稀疏的数据里,把生物学意义提取出来。
组学之间的关系
理解组学,先理解中心法则把它们分成的几个层次:
DNA ────────► RNA ────────► 蛋白
(基因组) (转录组) (蛋白组)
| 层次 |
它告诉你 |
主要技术 |
| 基因组(Genomics) |
这个个体有什么基因、有什么变异 |
WGS / WES / Panel 测序 |
| 转录组(Transcriptomics) |
哪些基因正在表达、表达多少 |
bulk RNA-seq / scRNA-seq |
| 蛋白组(Proteomics) |
哪些蛋白真的被合成出来、丰度多少 |
质谱 |
| 表观组(Epigenomics) |
哪些基因被"打开",调控状态如何 |
ATAC-seq / ChIP-seq / 甲基化 |
三个关键点:
- 上下层不一定一致。基因组上有的基因可能不转录,转录的也不一定都翻译成蛋白。
- 单组学数据是一个切片:只看转录组就好像只看一个时刻的快照。多组学整合就是在补上这部分缺失视角。
- 不同组学的分析流程底层逻辑相通(QC → 标准化 → 差异 → 富集),但每一层有自己的专用工具和坑。
把组学放进这个框架里,后面学的每一篇教程都能找到自己的位置。
组学数据的四个特点
每个特点都不只是一个描述,它决定了这条数据该怎么处理。
1. 数据量大 → 工具链整体是命令行 + 脚本
一次单细胞实验产生几十 GB 原始数据。Excel 打不开、记事本卡死,靠 GUI 工具点鼠标的工作流不再适用。学组学分析的前提是接受"工具链整体跑在命令行 + 脚本里"这件事。
2. 维度高 → PCA / UMAP 不是装饰,是必经之路
人类编码基因约 2 万,全转录组(含非编码 RNA)4-6 万。这意味着每个样本对应的向量有几万维。人脑无法在几万维里直接找规律,降维(PCA / UMAP / t-SNE)是把数据"翻译"成人能看的形式,不是为了好看。
3. 噪音多 → 永远看分布和重复,别看单点
生物学实验本身有变异(同一组织取两次切片不完全一样),测序技术也有误差(PCR 偏差、批次效应)。任何单一数据点都不可靠,下游分析要靠分布、重复、统计检验才能从噪音里捞出真信号。
4. 稀疏 → 单细胞要专门处理 dropout
单细胞数据里大量基因在大多数细胞中表达量为 0,部分是技术 dropout(基因实际表达但没测到),部分是真实未表达。对这种稀疏矩阵,普通线性方法(CPM / log)会失真,所以才有 SCTransform、scVI 这种专门的方法。
分析流程概览
一份组学项目从原始数据到结论,大致 9 步:
- 数据获取:从测序仪下机的 FASTQ 文件,或从 GEO/TCGA 等公共库下载
- 质量控制:检查测序质量、过滤低质量 reads(FastQC / MultiQC)
- 序列比对:把 reads 比对回参考基因组(Cell Ranger / STAR / BWA)
- 表达矩阵构建:统计每个基因在每个样本/细胞里的 reads 数
- 数据标准化:去掉测序深度差异(CPM / TPM / SCTransform)
- 降维 + 聚类:把高维数据投到 2D 看结构(PCA / UMAP),然后聚类
- 差异分析:比较组间表达差异,找标志基因
- 功能注释:用 GO / KEGG / GSEA 把基因列表翻译成生物学故事
- 可视化:热图、火山图、UMAP 等 — 让结果说话
这 9 步可以分成两段:
- 第 1-4 步是数据工程,产物是一份"基因 × 样本"的表达矩阵
- 第 5-9 步是分析与解读,产物是生物学结论
学习时这两段可以分开攻:先用现成矩阵跑通第 5-9 步(很多教程数据集自带矩阵),等对结果有感觉了再回头补 1-4 的数据工程。这样能更快建立成就感和判断力。
学习路径建议
第 1 阶段:能跑起来(2-4 周)
选一门主语言(推荐 R 起步,单细胞主流工具用 R),能完成最小可复现的小任务:
- 读一张表 → 做一次筛选 → 画一张图 → 保存结果 → 记录版本
强烈建议先看一眼 AI 辅助编程与智能体工具,了解什么时候该让 AI 帮忙、什么时候不该。
第 2 阶段:跑通完整流程(4-8 周)
跟着教程从原始数据走到最终结果。先不深究每个参数为什么这么选,优先把流程跑通一次。
推荐 单细胞实践 01-04。
第 3 阶段:理解每一步在做什么(2-3 个月)
回过头来看每一步的原理,调参看效果变化,读相关文献和工具文档。
推荐 单细胞实践 05-10。
第 4 阶段:独立做项目(持续)
用自己的或公开数据做完整分析。这一阶段标志是:遇到问题不再问"我该用什么工具",而是问"这个生物学问题最适合的方法是什么"。
常见误区
"工具越新越好"
新工具可能引用量很高但默认参数不一定稳。成熟工具(Seurat / DESeq2 / clusterProfiler)经过多年大量数据验证,先用它们建立基线再尝试新方法更稳妥。
"参数复杂 = 严谨"
绝大多数主流工具的默认参数已经是经过精心调过的。盲目调参可能把模型推到训练数据外的区域。理解参数含义比调参更重要。
"p < 0.05 就是好结果"
p 值只是统计学显著性,不代表生物学意义。一个 padj=1e-50 但 log2FC=0.1 的基因,统计上极显著,生物学上几乎没区别。要 padj 和 fold change 一起看。
"图越炫越有说服力"
清晰准确比炫酷重要。一张干净的散点图、火山图、热图比 3D 旋转图更能说服审稿人。把图当成证据,不是装饰。
持续学习
下一步
接着深入(按推荐顺序读下去):
- 编程基础 — 选定一门主语言,建立最小工作流
- 数据与环境准备 — 把后续脚本要的数据和包准备好,避免每次报错都查
- 单细胞实践 01:实践数据集与数据获取 — 第一个完整可跑的真实流程
横向延伸(任意时机看):
02 AI 辅助编程与智能体工具
AI 编程工具已经从"补全几行代码"发展到"阅读项目、修改文件、运行命令、检查结果"的智能体工作流。对组学数据分析来说,它们可以显著提高效率,但不能替代你对数据、统计方法和生物学问题的判断。
这一篇不追工具热点,目的是建立一套可靠的使用框架:什么时候用 AI、怎么交付任务、如何检查结果、哪些数据不能交给外部服务。
先记住一句话
AI 帮你打字,不替你思考。
打字层面(写一段代码、改一份脚本、生成测试)AI 越来越快,但思考层面(这份数据该不该用、这个统计方法对不对、这条结论能不能写)必须人来。
下面所有内容都围绕这一句展开。
什么是 vibe coding
Vibe coding 指用自然语言描述目标,让 AI 快速生成原型代码或应用。它适合探索想法,例如:
- 快速画一张表达量分布图
- 把一段 R 代码改写成 Python
- 根据报错信息定位可能原因
- 生成一个小型数据清洗脚本
- 搭一个分析报告模板
它的代价也直白:模型默认很多假设,生成的代码看起来能跑,但不一定统计上正确、可重复或适合真实数据。
所以 vibe coding 在 BioF3 的语境里只是"快速草稿",后续必须补上:
- 明确输入和输出
- 固定软件版本
- 保存参数和随机种子
- 人工检查统计方法
- 用小数据集验证结果
- 把一次性代码整理成可复现脚本
智能体工具和普通聊天的区别
普通聊天工具只回答问题。智能体工具可以连接代码环境,做更完整的开发动作:
- 读取项目文件
- 修改多个文件
- 运行终端命令
- 执行测试或构建
- 根据错误继续修复
- 生成提交说明或 Pull Request
权限越大,风险越高。第一次接入新工具时,先让它只读:让它解释项目结构、提出修改计划,确认无误后再允许它真的改文件。
常见工具类型
1. IDE 内置助手
嵌入编辑器,适合日常写代码、解释局部文件、生成函数和查看 diff。
常见形态:
- VS Code 插件
- Cursor 等 VS Code 衍生编辑器
- JetBrains 系列插件
- 云端 IDE 或浏览器工作区
适合做:解释当前脚本 / 补全函数 / 重构局部代码 / 修复语法错误 / 模仿现有风格写一段相似代码。
不适合做:没有上下文的大型分析决策 / 未确认就批量改整个项目 / 直接处理敏感临床数据。
2. Codex
Codex 是 OpenAI 的编码智能体,可以在终端、本地开发环境或相关产品界面中使用。适合读项目、改文件、运行命令、做代码审查和处理多文件任务。
codex
可以让它做:
梳理这个 Docusaurus 项目的目录结构,指出教程内容、静态资源和部署脚本分别在哪里。
检查 docs/single-cell/module02.md 里的 R 代码块,找出可能无法直接运行的地方,只给建议,不要修改文件。
使用建议:
- 先让 Codex 读项目并给计划
- 修改前确认影响范围
- 每次只给一个明确任务
- 改完后运行 build / 测试 / 示例脚本
- 不要把未脱敏数据、密钥、服务器凭据写进提示词
3. Claude Code
Claude Code 是 Anthropic 的编码智能体,可以在终端、IDE、桌面应用和浏览器中使用。能读代码库、编辑文件、运行命令,并和开发工具集成。
claude
适合做:解释陌生代码库 / 根据报错追踪问题 / 编写测试 / 批量修复 lint 或格式 / 整理项目文档 / 通过 CLAUDE.md 固定项目规则。
在生信项目中,可以这么用:
阅读这个 R 脚本,解释每一步在单细胞分析流程中的作用,并指出哪些参数需要根据数据集调整。
4. opencode
opencode 是开源的 AI 编码智能体,主打终端工作流,也提供桌面和 IDE 形态。可以连接不同模型供应商,适合希望掌控工具栈和模型来源的开发者。
opencode
适合做:本地项目问答 / 生成修改计划 / 实施局部功能 / 维护项目级 AGENTS.md / 在多个模型之间切换。
特别注意:API key 千万不要写进仓库,不要提交 .env。
5. Kiro
Kiro 是偏"规格驱动开发"的 AI IDE。先把需求、设计、任务拆清楚,再让智能体执行。相比纯 vibe coding,它更适合把原型推进到可维护项目。
核心概念:
- specs:把需求、设计、任务写成结构化文档
- steering:给项目提供长期规则和上下文
- hooks:在保存、创建或删除文件时触发自动化任务
- agentic chat:通过自然语言和项目交互
适合做:从想法生成需求说明 / 把功能拆成可检查任务 / 生成实现计划和测试计划 / 维护中大型项目的一致性。
如果只是临时画一张图,Kiro 偏重;如果要长期维护一个网站、分析平台或工作流,它的规格驱动思路有价值。
6. API 中转站和模型聚合服务
很多用户会接触到"中转站"、"转发站"或"模型聚合服务"。它们提供统一 API,把请求转发到不同模型供应商。
优点:一个接口访问多个模型 / 支付和额度管理可能更方便 / 有些服务提供兼容 OpenAI 格式的接口。
风险:
- 数据会经过第三方服务
- 稳定性和响应速度不可控
- 模型版本、价格、上下文长度可能变化
- 数据保留策略可能不透明
- 不适合处理未公开论文、临床数据、密钥、商业代码
建议:能用官方 API 或企业账号时优先用 / 不把真实患者数据、访问密钥、服务器密码交给不明中转服务 / 如必须使用中转,先做脱敏和小样本测试 / 在项目文档中记录模型、供应商、日期和关键参数。
生信分析中的安全边界
AI 工具擅长写代码,但不理解真实实验约束。下面这些事情必须由人来确认:
- 样本分组是否正确
- 统计检验是否匹配实验设计
- 批次效应是否需要处理
- marker gene 是否符合生物学背景
- 过滤阈值是否合理
- 可视化是否夸大结论
- 结果是否可重复
对涉及人类样本、临床数据、未公开项目的数据,先默认不能上传到外部 AI 服务。至少要做:
- 去除姓名、编号、地址等直接标识符
- 去除可回溯到个体的元数据
- 不上传原始 FASTQ、BAM、全量表达矩阵
- 只提供最小可复现示例
- 改用本地模型、企业合规服务或脱敏后的样例数据
推荐工作流
学习阶段:把 AI 当解释器,不是代写器
用初学者能理解的方式解释这段 Seurat 代码。请逐行说明输入、输出和关键参数。
我不理解 NormalizeData、FindVariableFeatures、ScaleData 的区别。请结合单细胞表达矩阵解释。
分析阶段:AI 出草稿,保留人工审查
根据这个数据框结构,写一段 ggplot2 代码画不同细胞类型的基因表达小提琴图。请不要假设不存在的列名。
下面是报错信息和 sessionInfo。请判断最可能的原因,先给排查步骤,不要直接改代码。
项目维护阶段:让 AI 做重复劳动
检查 docs/basics 目录下的教程,找出标题层级不一致、图片路径可能错误、代码块语言未标注的问题。
为这个分析脚本生成 README,说明输入文件、输出文件、依赖包和运行命令。
提示词模板
解释代码
请解释下面这段代码。要求:
1. 说明每一步的目的
2. 标出输入和输出
3. 指出可能需要根据数据修改的参数
4. 不要重写代码,除非发现明确错误
生成分析脚本
请写一个可复现的 R 脚本完成以下任务:
- 输入:counts.csv 和 metadata.csv
- 输出:QC 图、标准化后的对象、marker 基因表
- 要求:固定随机种子,记录 sessionInfo,所有输出写入 results/
- 不要使用不存在的列名;如果需要列名,请先向我确认
审查结果
请作为代码审查者检查这段分析流程:
1. 是否有统计学问题
2. 是否有不可复现的步骤
3. 是否有硬编码路径
4. 是否遗漏中间结果保存
5. 是否需要补充图注或方法说明
常见坑
坑 1:AI 编出"看起来对"的列名
让 AI 写一段处理 metadata.csv 的代码,它经常猜列名("sample"、"group"、"condition"),生成看似可运行的代码,跑起来 Error in $: object 'group' not found。
避免:把真实列名(或 head() 输出)一起喂给 AI,明确告诉它"不要假设不存在的列名"。
坑 2:AI "幻觉"出不存在的函数 / 包
特别在跨语言(R ↔ Python)翻译时,AI 会编出根本不存在的函数。代码看起来很对,跑起来 could not find function。
避免:每次拿到 AI 写的代码,先把所有 library() / import 列出来核对一遍,再跑。
坑 3:把临床数据原文贴进对话
学生最常见的事故。"老师让我分析这份病人数据",复制粘贴整张表到 ChatGPT,姓名、住院号、确诊日期一并送出。
避免:在做任何分析前,先脱敏一份"开发用样例",所有 AI 交互只针对样例。真实数据只在本地分析。
坑 4:把 API key 写进代码,提交到 git
client <- httr2::request("https://api.openai.com/v1/...") |>
httr2::req_headers(Authorization = "Bearer sk-xxxxxxxxxxxx")
提交 git → 推到 GitHub → 公开 repo → key 被爬虫扫到 → 余额清零。
避免:所有 key 放 .env 或环境变量,.env 加进 .gitignore。
坑 5:让 AI "一次性写完整套分析"
提示词:"写一个完整的单细胞 RNA-seq 分析脚本,包括 QC、标准化、聚类、注释、差异分析、富集"。AI 真的会给你 200 行代码,但每一步都用了它"觉得最常用"的参数 / 阈值 — 不一定适合你的数据。
避免:拆成"按一步一步"。每一步:先让 AI 解释这一步在做什么,再让它写代码,再人工跑一下,看输出。然后才进下一步。
工具选择建议
| 场景 |
更适合的工具 |
| 解释一段代码 |
ChatGPT、Claude、IDE 助手 |
| 修改本地项目多个文件 |
Codex、Claude Code、opencode |
| 快速原型 |
Codex、Claude Code、Cursor、Kiro |
| 规范化长期项目 |
Kiro、Codex、Claude Code |
| 多模型切换 |
opencode、模型聚合服务 |
| 敏感数据分析 |
本地部署的开源模型(Ollama 等)/ 企业合规服务 / 完全离线工具 |
下一步
接着深入(按推荐顺序):
- 编程基础:R / Python / Bash — 把 AI 帮你写的代码看懂、改对,前提是你自己会一点
- 数据与环境准备 — 先把环境装好,AI 写的代码才能在你机器上跑
横向延伸:
参考资料
03 编程基础:R / Python / Bash
做组学数据分析,编程不是目标,而是工具。目标不是成为程序员,是能:
- 读懂别人的脚本
- 修改参数让它跑自己的数据
- 看懂报错并找到原因
- 把分析过程整理成可重复的记录
这一篇给出 BioF3 推荐的最小学习路径。
为什么必须学编程
组学数据有三个特点,让点鼠标的工作流彻底失效:
- 数据量大:表达矩阵、FASTQ、BAM、H5AD 文件动辄几个 GB,Excel 打不开
- 步骤多:QC、标准化、降维、聚类、差异分析、富集分析…每一步都有参数要记
- 结果要可复现:论文、报告、协作场景都需要"别人能跑一遍得到一样的图"
光靠点鼠标,下面这些问题答不出来:
- 这次分析用了哪些过滤阈值?
- 归一化和聚类参数是什么?
- 哪张图是哪一步生成的?
- 换一批样本能不能自动重跑?
- 半年后还能不能复现同样结果?
编程的价值就是把分析过程写下来,让它可以检查、重复、修改、共享。
BioF3 推荐工具栈
R:单细胞分析和统计可视化主力
BioF3 的单细胞实践主要用 R 生态。先学 R 是最直接的路径。
常见场景:
- Seurat 单细胞分析
- ggplot2 可视化
- DESeq2 / edgeR / limma 差异表达
- 统计检验和建模
- clusterProfiler 富集分析
- R Markdown / Quarto 报告
最低要求:
- 读写 CSV、TSV、RDS
- 用 data.frame / tibble
- 用 dplyr 做筛选、分组、排序、汇总
- 用 ggplot2 画常见图
- 安装和加载包
- 看懂函数参数和报错信息
Python:数据处理、机器学习和 Scanpy 生态
Python 适合处理大规模数据、机器学习、工程化流程。
常见场景:
- pandas / numpy 数据处理
- Scanpy / AnnData 单细胞分析
- scikit-learn 机器学习
- PyTorch 深度学习
- 自动化脚本和 API 调用
- 文件批处理
最低要求:
- 创建虚拟环境(venv / conda)
- 读写 CSV、TSV、JSON、H5AD
- 用 pandas 做表格处理
- 用 matplotlib / seaborn 画图
- 写简单函数
- 根据 traceback 定位错误
Bash:服务器和生信流程的入口
很多生信工具只有命令行版本。不会 Bash,就用不稳服务器和高通量流程。
常见场景:
- 查看和移动文件
- 解压、统计、合并文件
- 批量运行 FastQC、Cell Ranger、STAR、samtools
- 后台任务和日志检查
- 远程服务器操作
- 写 shell 管道和脚本
最低要求:
cd / ls / cp / mv / mkdir / rm
head / tail / less / wc
grep / awk / sed 基本用法
- 写简单
for 循环
- 重定向输出和查看日志
- 用
ssh 登录服务器
AI:助教 + 排错助手 + 草稿生成器
适合让 AI 做的:解释陌生代码 / 把报错翻译成排查步骤 / 生成脚本草稿 / 改写重复代码 / 生成 README / 检查路径和变量名。
不适合完全交给 AI 的:决定实验分组 / 决定统计检验 / 判断 marker gene / 解释疾病机制 / 处理未脱敏临床数据 / 编造软件版本和文献依据。
更完整的工具介绍和提示词模板见 AI 辅助编程与智能体工具。
学习顺序
跟 组学入门 的 4 阶段呼应,编程层面这样切:
第 1 阶段(搭配 overview 第 1 阶段):能跑、能改
新手最容易陷入"先系统学完整门语言"的误区。优先目标是能跑通别人写的脚本。
能做到这几件事就够:
- 打开 RStudio / Jupyter / 终端
- 运行一段教程代码
- 修改输入文件路径
- 修改过滤阈值
- 保存结果图和结果表
练习:
拿一份 BioF3 教程脚本,把输入文件路径改成自己的目录,
把输出目录改成 results/,跑一遍,确认产出在该出现的位置。
第 2 阶段(搭配 overview 第 2 阶段):R 入门到可用
先掌握基础数据结构:
genes <- c("TP53", "BRCA1", "EGFR")
expr <- c(5.2, 3.8, 7.1)
gene_data <- data.frame(gene = genes, expression = expr)
head(gene_data)
str(gene_data)
summary(gene_data)
high_expr <- gene_data[gene_data$expression > 5, ]
再学 dplyr 风格:
library(dplyr)
gene_data <- gene_data %>%
mutate(log_expression = log2(expression + 1)) %>%
arrange(desc(expression))
最后 ggplot2:
library(ggplot2)
ggplot(gene_data, aes(x = gene, y = expression)) +
geom_col(fill = "#3B82F6") +
labs(x = "Gene", y = "Expression") +
theme_classic()
R 阶段目标不是语法完美,是能读懂 Seurat 教程里的对象、函数、参数。
第 3 阶段(搭配 overview 第 2-3 阶段):Python 入门到可用
Python 先从 pandas 开始:
import pandas as pd
import numpy as np
data = pd.DataFrame({
"gene": ["TP53", "BRCA1", "EGFR"],
"expression": [5.2, 3.8, 7.1],
})
data["log_expression"] = np.log2(data["expression"] + 1)
high_expr = data[data["expression"] > 5]
print(data["expression"].mean())
画图先掌握 matplotlib + seaborn:
import seaborn as sns
import matplotlib.pyplot as plt
sns.barplot(data=data, x="gene", y="expression", color="#3B82F6")
plt.xlabel("Gene")
plt.ylabel("Expression")
plt.tight_layout()
plt.show()
Python 阶段目标是能处理表格数据、看懂 Scanpy / AnnData 对象、能写小型自动化脚本。
第 4 阶段(搭配 overview 第 3-4 阶段):Bash 入门到可用
文件和目录:
pwd
ls -lh
mkdir -p results/qc
cp data/sample.csv results/
查看文件:
head expression.tsv
tail -n 20 run.log
wc -l expression.tsv
less run.log
批量处理:
mkdir -p qc_results
for file in data/*.fastq.gz; do
echo "Processing $file"
fastqc "$file" -o qc_results/
done
远程服务器:
ssh aliyun
scp results/report.html aliyun:/opt/project/results/
Bash 阶段目标是能在服务器上找到文件、运行工具、检查日志、批量处理样本。
一个最小可复现项目结构
从第一个项目开始,就用固定结构组织文件:
project/
├── data/
│ ├── raw/ # 原始数据,永远不动
│ └── processed/ # 中间产物
├── scripts/
│ ├── 01_qc.R
│ ├── 02_normalize.R
│ └── 03_plot.R
├── results/
│ ├── figures/ # 图
│ └── tables/ # 表
├── logs/ # 运行日志
└── README.md # 顺序、版本、参数
为什么这种结构值得:
data/raw/ 永远不动 → 任何中间步骤跑出问题都能从原始数据重来
- 脚本编号
01_ 02_ 03_ → 一眼看出执行顺序
results/figures/ 和 results/tables/ 分开 → 写论文时能直接捞图
- README 列清"运行哪个脚本、需要什么版本、产出在哪" → 半年后自己看才认得这个项目
常见坑
坑 1:报错只看最后一行
R / Python 报错通常很长,新手习惯只看最后一行的红字,结果定位不到真实问题。真实原因往往在 traceback 中段。
避免:完整复制整段报错,从下往上读,找到第一个你自己代码的位置(不是 library 内部的)。
坑 2:路径写绝对路径,换机器就崩
read.csv("/Users/zhangsan/data/sample.csv") — 自己电脑能跑,发给同事就 file not found。
避免:用相对路径 read.csv("data/sample.csv"),配合 setwd() 或 RStudio Project 固定项目根目录。
坑 3:包版本不固定,半年后跑不出来
Seurat v4 → v5 函数签名大改,跑不动同一个脚本。
避免:每个项目里跑 sessionInfo() 或 pip freeze 把版本记进 README,关键时候用 renv(R)或 conda env(Python)锁版本。
坑 4:循环里改变量名重复了
for (i in 1:length(samples)) {
i <- samples[i]
...
}
避免:循环变量和值用不同名字。for (idx in seq_along(samples)) { sample <- samples[idx]; ... }。
坑 5:把数据变量名跟函数名重叠
data <- read.csv("foo.csv")
mean <- mean(data$expr)
后面再调 data() 或 mean() 就会困惑。
避免:用更具体的名字 — expr_data、expr_mean、pbmc_counts 等。
常见问题
没有基础,先学 R 还是 Python?
如果目标是尽快进入单细胞分析,先学 R。BioF3 单细胞主线工具用 R / Seurat。Python 可以等学到 Scanpy、机器学习、自动化时再补。
Bash 一定要学吗?
最基础的部分要学。不需要成为 Linux 专家,但要能在服务器上找到文件、运行命令、查看日志。否则很多上游流程(Cell Ranger、STAR)直接卡住。
可以全靠 AI 写代码吗?
不行。AI 可以写草稿,但必须人工确认输入数据、列名、统计方法、输出结果和生物学解释。涉及临床数据和未公开项目时,原始数据不要直接上传给外部 AI 服务。详见 AI 辅助编程与智能体工具 的"安全边界"和"5 个常见坑"。
报错时怎么处理?
按这个顺序:
- 完整复制报错(不只看最后一行)
- 确认对象是否存在、路径是否正确、包是否加载
- 用小数据集复现问题
- 搜索错误信息
- 让 AI 根据代码、报错、环境信息给排查步骤
- 修复后把原因记进 README 或 commit message
学到什么程度可以开始跑单细胞教程?
能做到这几件事就够:
- 运行 R 脚本
- 安装和加载 R 包
- 修改文件路径
- 查看 R 对象的基本信息(
str() / head() / dim())
- 保存图和表
- 根据报错做基础排查
下一步
接着深入(按推荐顺序读下去):
- 数据与环境准备 — 先把环境装好,避免每次跑教程脚本都报"找不到包"
- R 数据整理与 ggplot2 可视化 — R 阶段最值得先精通的两件事
- 单细胞实践 01:实践数据集与数据获取 — 用真实流程检验你学到的语法
横向延伸:
编程能力不是背语法背出来的,是在真实任务里练出来的。最快的开始方式:拿一张表,完成"读 → 筛 → 画 → 存"四件事。
04 Jupyter 与交互式分析环境
组学分析的第一个工程问题是:在哪里写下可以重复运行的分析过程?
Jupyter Notebook 是最常见的答案。它把代码、说明、图表和运行结果放在一份文档里,适合探索性分析和教学演示。
但 Notebook 不是万能的。这一篇把它的用法和边界都说清楚 — 哪些事 Notebook 该做、哪些事必须用脚本。
Notebook 是什么、不是什么
适合 Notebook 做的事
- 记录分析思路(每跑一段代码补一段 Markdown 解释)
- 逐步运行代码并立刻看结果
- 快速查看表格 / 图
- 解释参数选择的理由
- 分享小型分析示例 / 教学
不适合 Notebook 做的事
- 长时间无人值守的大流程(Cell Ranger / STAR 这种小时级任务)
- 大规模批处理(一次跑 100 个样本)
- 不能版本控制的正式生产流程
- 敏感数据输出(Notebook 默认会把输出嵌到文件里,临床数据进 git 就尴尬了)
核心判断:Notebook 是"探索 + 记录"载体,不是"执行 + 部署"载体。稳定下来的步骤应该整理到 .R / .py 脚本里。
四种常见环境
1. Jupyter Notebook(经典界面)
适合初学者起步。文件 .ipynb,内部保存代码单元、Markdown 文本、输出结果。
pip install notebook
jupyter notebook
2. JupyterLab(推荐)
更完整的工作界面:Notebook + 终端 + 文本编辑器 + 文件浏览器一体。真实项目里基本都用 JupyterLab。
pip install jupyterlab
jupyter lab
3. Google Colab(云端,临时用)
打开浏览器就能跑 Python。免费用户也能用 GPU。
适合:快速试代码 / 课堂演示 / 共享小型 Notebook / 临时用 GPU 跑一下深度学习。
不适合:
- 长期保存重要环境(会话经常断)
- 处理隐私 / 临床数据(数据上传 Google)
- 安装量大的依赖(每次启动都要重装)
4. 服务器 Notebook(真实项目首选)
数据在服务器上时,把 JupyterLab 起在服务器,浏览器通过 SSH 端口转发访问。
服务器端:
ssh aliyun
cd /path/to/project
conda activate sc-env
jupyter lab --no-browser --port 8888
本地终端:
ssh -L 8888:localhost:8888 aliyun
注意权限、数据路径、端口安全(不要把 8888 直接暴露公网)。
在 R 里也能用 Notebook
.ipynb 不只是 Python 的。装一个 IRkernel,就能在 Jupyter 里跑 R。
install.packages("IRkernel")
IRkernel::installspec()
之后启动 JupyterLab,新建 Notebook 时能选 R 内核。Seurat / DESeq2 / ggplot2 都能直接在里面跑,输出图也能内嵌。
备选:很多 R 用户直接用 RStudio + R Markdown / Quarto,效果跟 Notebook 类似。单纯做 R 分析不一定非要 Jupyter。Jupyter 的优势在 Python 重,或者多语言混合的项目。
Notebook 的基本结构
每个 Notebook 由一组**单元(cell)**组成,主要两种:
Markdown 单元 — 写说明
## 质量控制
本步骤过滤低质量细胞:
- `nFeature_RNA < 200`:基因数太少的可能是空 droplet
- `percent.mt > 20`:线粒体比例高的可能是死细胞或破损
Code 单元 — 跑代码
import pandas as pd
metadata = pd.read_csv("data/metadata.csv")
metadata.head()
输出(表 / 图 / 错误信息)会显示在单元下方,并保存进 .ipynb 文件。
把环境记下来
每个 Notebook 跑完都建议在最后加一个版本记录单元:
Python:
import sys, pandas as pd, numpy as np
print(sys.version)
print(pd.__version__, np.__version__)
R:
sessionInfo()
这一段救过无数"半年前的我跑得动,现在跑不出来"的事故。
从 Notebook 走向脚本
Notebook 的价值不是"把所有分析塞在一个文件里"。稳定下来的部分应该走出 Notebook。
判断"该不该走"的几条原则:
- 同一段代码改了 3 次以上 → 抽到函数,放进
scripts/utils.R
- 这段分析要给同事跑 / 给老板跑 / 自动化重复跑 → 整理成命令行脚本
- 步骤太长、Notebook 滚不到底 → 拆成多个 Notebook,或拆成脚本
- 包含敏感数据 → 立刻搬出 Notebook(输出会被保存到
.ipynb 里)
推荐结构:
project/
├── notebooks/ # 探索性 + 教学 Notebook
├── scripts/ # 稳定可复现脚本
├── data/
└── results/
常见坑
坑 1:Notebook 里的代码跑顺序乱了
Notebook 允许任意顺序运行单元,变量状态不一定跟你看到的顺序一致。新手常常跑出"看着都跑过但结果不对"的玄学情况。
避免:定期点 "Restart Kernel & Run All",确保从头到尾顺次跑下来还是同样结果。这是 Notebook 可复现性的核心保证。
坑 2:把 .ipynb 提交进 git,diff 一片乱码
.ipynb 是 JSON 格式,包含 base64 编码的图片输出。每次重跑都生成不同 metadata,git diff 完全不可读。
避免:
- 提交前清空输出(Cell → All Output → Clear)
- 或装
nbstripout 自动在 commit 时剥掉输出
- 或改用
.py + Jupytext,把 Notebook 双向同步成纯 Python
坑 3:把临床数据载进 Notebook,输出嵌进文件,提交 git
直接违规。患者数据原文进了 Notebook 输出,再随手 git push,敏感信息泄漏到公开仓库。
避免:临床 / 未脱敏数据永远不在 Notebook 里直接展示原文。脱敏到样例数据,分析跑在样例上;真实数据只在合规环境处理,输出不嵌进 .ipynb。
坑 4:依赖 Notebook 里 !pip install,环境没固定
调试时图省事,在 Notebook 里 !pip install scanpy 装包。当时能跑,几个月后版本不一致跑不出。
避免:用项目级环境(environment.yml / requirements.txt / renv.lock),Notebook 只 import,不在里面装包。
坑 5:Notebook 越写越长,最后跑一次要 30 分钟
探索性分析很容易越写越长,跑一次几十分钟,每改一处都要全跑。
避免:定期把"这一段已经稳了"的部分搬到 scripts/,Notebook 只保留当前在调的部分。或者把中间产物 pickle / saveRDS 存到磁盘,下次直接加载。
下一步
接着深入:
- 数据与环境准备 — 在 Notebook 里
import seurat 之前,先把环境搭好
- R 数据整理与 ggplot2 可视化 — Notebook 里画图的能力直接决定它有多好用
- 单细胞实践 01 — 第一个完整可跑的真实流程,是 Notebook 还是脚本看自己习惯
横向延伸:
参考资源
05 公共数据库与数据检索
组学分析常常不从自己测序开始,而是先用公开数据练手 / 验证假设 / 做对照。
这一篇回答两个问题:
- 从哪里找数据 — 主流公开库有哪些、各自擅长什么
- 怎么判断数据合不合适 — 不是任何编号能下到的数据都能用
先看你需要什么类型的数据
不同数据库的产出形态完全不同:
| 你需要 |
优先看哪里 |
| 找某篇论文的配套表达矩阵 |
GEO |
| 下载原始 FASTQ |
SRA / ENA |
| 浏览已注释的单细胞数据 |
CELLxGENE |
| 找人类细胞参考图谱 |
HCA Data Portal |
| 查某个基因在哪些组织表达 |
Expression Atlas |
| 找癌症基因组 + 临床数据 |
TCGA / GDC |
| 找表观调控(peak / motif)数据 |
ENCODE |
| 找人类群体遗传变异 |
1000 Genomes / gnomAD |
下文每一个都有最低限度介绍。先确定需求、再选库。"先去 GEO 搜搜"是浪费时间的常见做法。
常见 accession 编号
公开数据通过 accession 编号追踪。每个库有自己的编号体系:
| 编号 |
含义 |
示例 |
| GSE |
GEO Series,一个研究 |
GSE12345 |
| GSM |
GEO Sample,一个样本 |
GSM123456 |
| GPL |
GEO Platform,测序平台 |
GPL16791 |
| SRP |
SRA Study |
SRP123456 |
| SRX |
SRA Experiment |
SRX123456 |
| SRR |
SRA Run,真正能下载 reads 的层级 |
SRR1234567 |
| ERP / ERX / ERR |
ENA 对应 SRA |
ERR1234567 |
| TCGA-XX-XXXX |
TCGA case barcode |
TCGA-A1-A0SK |
| ENCSR |
ENCODE Series |
ENCSR000AAA |
最常见的坑:拿到 GSE 直接找 FASTQ 下不到。FASTQ 在 SRR 层级,需要顺着 GSE → GSM → SRX → SRR 追。
主要数据库
GEO(Gene Expression Omnibus)
NCBI 维护,覆盖功能基因组学最广。论文发表时强制要求把数据上传 GEO,所以"找论文配套数据"几乎必经此处。
检索关键词模板:
关键词 + 物种 + 技术 + 组织/疾病
例:
single cell RNA-seq human liver fibrosis
PBMC scRNA-seq healthy donor
SRA / ENA(原始测序数据)
需要 FASTQ 时基本都到这两家。NCBI 的 SRA 和 EBI 的 ENA 内容是镜像的,下载时哪个快用哪个。
下载工具:
conda install -c bioconda sra-tools
prefetch SRR1234567
fasterq-dump SRR1234567 --split-files -O data/raw/
注意:
- 一个 SRR 几个 GB 到几十 GB,先确认磁盘空间
- 批量下载前先用一个 SRR 测试网络
- 记录 SRR 列表和下载日期,方便后续溯源
CELLxGENE Discover(单细胞已注释)
CZI(Chan Zuckerberg Initiative)维护,专注单细胞数据的可视化浏览。
适合:
- 在下载前先在线看一眼数据(细胞数、注释、是否有你关心的基因)
- 下载
.h5ad 直接在 Scanpy 里加载
- 比较"我的数据" vs "公开同类数据"
Human Cell Atlas(HCA Data Portal)
国际合作的人类细胞图谱项目,目标是给所有人体组织 / 器官生成参考图谱。
适合:
- 找参考图谱(比如要做细胞类型注释时的"答案集")
- 接入大型数据整合分析
- 看权威标注的数据
Expression Atlas / Single Cell Expression Atlas
EMBL-EBI 的基因表达查询库。适合"查一个基因",不适合"下大数据集"。
适合:
- 查
TP53 在哪些组织高表达
- 做初步假设(这个基因可能在某细胞类型里特异表达)
- 给报告 / 演讲补一张参考图
TCGA / GDC(癌症基因组图谱)
NCI 主导的癌症大队列。包含 33 种癌症约 11000 个样本的基因组、转录组、甲基化、临床信息。
适合:
- 肿瘤研究的对照数据 / 验证集
- 大队列统计分析
- 多组学整合教学
注意 dbGaP 限制 — 部分数据需要授权。
ENCODE(表观调控元件百科全书)
DOE / NIH 主导,主要提供 ChIP-seq / ATAC-seq / DNase-seq / RNA-seq 等 functional 数据。
适合:
- 找 motif / peak 标准数据集
- 表观调控研究的基线
- 跨细胞系 / 跨条件比较
1000 Genomes / gnomAD(人类变异)
群体遗传 / GWAS / 临床变异解读绕不开的两个库。
适合:
- 查变异在群体里的频率
- 临床变异分级时排除常见多态性
- 群体遗传学分析
怎么判断一个数据集合不合适
下载前先用这份清单过一遍,比下完发现不能用强:
1. 物种和参考版本
- 物种是不是你研究的(小鼠 vs 人)
- 参考基因组版本是不是兼容(hg19 vs hg38;mm10 vs mm39)
2. 实验设计
- 样本量够不够(差异分析至少每组 3 个生物学重复)
- 分组是否合理(有没有合适的对照)
- 有没有混淆变量(比如所有处理样本都是同一天测的,批次和处理混在一起)
3. 测序深度和数据规模
- bulk RNA-seq:建议每样本 ≥ 20M reads
- scRNA-seq:每细胞 ≥ 10000 UMI、≥ 1500 genes 是基本线
- WGS:30x;WES:100x
4. 元数据完整度
- 样本元数据有没有列清楚(年龄、性别、处理时间、技术批次)
- 没有元数据的数据基本不能用 — 你不知道每个 SRR 是哪个条件
5. 数据是原始还是处理过的
- 处理过的(已 normalize / 已 batch correct)→ 适合快速验证假设
- 原始 FASTQ → 适合自己重做流程,但下载和计算成本高
6. License 和使用限制
- 大多数 GEO / SRA 数据是 CC0(自由用)
- TCGA 部分数据需要 dbGaP 授权
- 临床相关数据可能有 IRB 限制
- 写论文前确认是否需要引用 / 获得授权
常见坑
坑 1:拿到 GSE 直接找 FASTQ
GSE 层级常常没有直接的 FASTQ 链接。需要顺着 GSE → GSM → SRX → SRR 找到 run 层级才能下。
避免:在 GEO 页面找 "SRA" 链接,跳到 SRA Run Selector,下载所有 SRR 列表,再批量下。
坑 2:把原始 reads 当成 counts 用
有些教程把 GEO 上的 *_counts.txt.gz 当作可直接喂 DESeq2 的输入。但 GEO 上传的"counts"可能是:raw counts / TPM / RPKM / 已 batch correct / 已 quantile normalize。
避免:每个数据集先看 README 和原始论文,确认是什么形态。DESeq2 要 raw integer counts,不是 TPM。
坑 3:参考基因组版本不一致
下了 GSE 的 BAM 文件,发现是 hg19 比对的;自己的新数据是 hg38。坐标对不上,下游 region 注释全错。
避免:下载前看清版本。需要时用 liftOver 转换,或重新比对原 FASTQ 到一致版本。
坑 4:元数据匹配不上
GEO 元数据里的样本顺序和表达矩阵列名顺序不一致。直接合并会把 sample A 的处理标签贴到 sample B 上。
避免:每次合并元数据和表达矩阵前,显式 join by sample ID,不要依赖默认顺序。
坑 5:忽略数据上传日期
2014 年的 PBMC 单细胞数据用的是 SMART-seq2,跟现在的 10x Chromium 不能直接比。十年前的 ChIP-seq 没有 input control 是常见情况。
避免:注意数据生成年份和当时的技术状态。老数据值得参考但不一定能直接整合。
AI 辅助检索
让 AI 帮你做:解析复杂检索结果 / 把 GSE 元数据整理成表 / 写下载脚本草稿。
不让 AI 做:判断数据集质量 / 决定研究问题 / 替你看论文摘要里的实验细节。
详见 AI 辅助编程与智能体工具。
下一步
接着深入:
- 数据与环境准备 — 下载下来的数据放哪、用什么环境跑
- 单细胞实践 01:实践数据集与数据获取 — 第一个真实流程,配套用 PBMC 3k 公开数据
横向延伸:
参考资源
速答
Q: 生信分析必须学 R 吗?
A: 不是必须,但强烈推荐。Seurat(单细胞)、DESeq2(差异分析)、clusterProfiler(富集)等核心包都是 R 生态。Python 有 Scanpy 等替代,但 R 在统计可视化和 Bioconductor 生态上仍占优。
Q: ggplot2 的图层语法核心是什么?
A: data + aesthetic + geometry 三件套。数据映射到美学属性(x/y/color),再叠加几何图层(点/线/柱)。图层之间用 + 连接,可以无限叠加。
Q: dplyr 最常用的 5 个函数?
A: filter()(筛选行)、select()(选列)、mutate()(新增列)、group_by() + summarize()(分组汇总)、arrange()(排序)。覆盖 90% 日常数据整理需求。
06 R 数据整理与 ggplot2 可视化
R 在组学分析中最常用的场景有两个:整理表格数据,画出能解释结果的图。对 BioF3 来说,本章不是追求完整覆盖 R 语言,而是让你掌握最常用、最容易迁移到真实项目的能力。
本章所有图表都来自公开数据集 10x Genomics PBMC 3k。它包含一名健康供体外周血单个核细胞的真实单细胞 RNA-seq 表达矩阵。
R 在 BioF3 中承担什么角色
R 不是唯一选择,但它在生信里非常重要:
- Seurat 是单细胞分析的主流工具之一
- Bioconductor 提供大量组学分析包
- ggplot2 和 ComplexHeatmap 适合发表级可视化
- R Markdown / Quarto 适合生成分析报告
学习 R 的重点不是背语法,而是知道数据对象长什么样、函数需要什么输入、结果如何保存。
准备真实 PBMC 3k 数据
先读取真实表达矩阵。完整脚本会自动下载数据;这里保留核心逻辑,方便你理解后续对象从哪里来。
library(Matrix)
library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)
data_dir <- file.path(path.expand("~"), "biof3-data", "pbmc3k")
matrix_dir <- file.path(data_dir, "filtered_gene_bc_matrices", "hg19")
pbmc_url <- paste0(
"https://cf.10xgenomics.com/samples/cell-exp/1.1.0/pbmc3k/",
"pbmc3k_filtered_gene_bc_matrices.tar.gz"
)
pbmc_tar <- file.path(data_dir, "pbmc3k_filtered_gene_bc_matrices.tar.gz")
dir.create(data_dir, recursive = TRUE, showWarnings = FALSE)
if (!file.exists(pbmc_tar)) {
download.file(pbmc_url, destfile = pbmc_tar, mode = "wb")
}
if (!file.exists(file.path(matrix_dir, "matrix.mtx"))) {
untar(pbmc_tar, exdir = data_dir)
}
counts <- readMM(file.path(matrix_dir, "matrix.mtx"))
genes <- read.delim(file.path(matrix_dir, "genes.tsv"), header = FALSE)
barcodes <- read.delim(file.path(matrix_dir, "barcodes.tsv"), header = FALSE)
rownames(counts) <- make.unique(genes[[2]])
colnames(counts) <- barcodes[[1]]
counts <- as(counts, "CsparseMatrix")
把矩阵整理成几张常用表:
mt_genes <- grepl("^MT-", rownames(counts))
qc <- data.frame(
cell = colnames(counts),
nCount_RNA = as.numeric(colSums(counts)),
nFeature_RNA = as.numeric(colSums(counts > 0)),
percent_mt = as.numeric(colSums(counts[mt_genes, , drop = FALSE]) / colSums(counts) * 100)
)
gene_summary <- data.frame(
gene = rownames(counts),
total_counts = as.numeric(rowSums(counts)),
detected_cells = as.numeric(rowSums(counts > 0))
) %>%
mutate(mean_counts = total_counts / ncol(counts))
marker_genes <- c("IL7R", "CCR7", "S100A8", "S100A9", "MS4A1", "CD79A", "NKG7", "GNLY", "PPBP")
marker_genes <- marker_genes[marker_genes %in% rownames(counts)]
marker_long <- bind_rows(lapply(marker_genes, function(gene) {
data.frame(
cell = colnames(counts),
gene = gene,
counts = as.numeric(counts[gene, ]),
log_counts = log1p(as.numeric(counts[gene, ]))
)
}))
这几张表分别回答不同问题:
counts:基因 x 细胞的稀疏表达矩阵
qc:每个细胞的总 UMI、检测基因数、线粒体比例
gene_summary:每个基因的总表达量和检出细胞数
marker_long:常见 PBMC marker 基因的长表表达量
最小 R 基础
向量
向量是 R 中最基础的数据结构。这里的基因名来自 PBMC 3k 矩阵中真实存在的 marker 基因。
genes <- marker_genes[1:4]
expression <- gene_summary$total_counts[match(genes, gene_summary$gene)]
genes[1]
expression > median(expression)
mean(expression)
数据框
数据框类似表格,是生信分析中最常见的数据形态。
gene_data <- gene_summary %>%
filter(gene %in% marker_genes) %>%
select(gene, total_counts, detected_cells, mean_counts)
head(gene_data)
str(gene_data)
summary(gene_data)
访问列:
gene_data$gene
gene_data[["total_counts"]]
筛选行:
high_detection <- gene_data[gene_data$detected_cells > 100, ]
列表
很多 R 包会把复杂结果放在列表里。Seurat 对象、差异分析结果和富集分析结果都可能包含多层信息。
analysis_result <- list(
counts = counts,
qc = qc,
marker_expression = marker_long
)
analysis_result$qc
dplyr:表格整理的基本动作
先加载包:
library(dplyr)
用真实基因汇总表练习筛选、排序和新增列:
top_genes <- gene_summary %>%
filter(!grepl("^MT-|^RPL|^RPS", gene)) %>%
filter(detected_cells > 50) %>%
arrange(desc(total_counts)) %>%
mutate(
log_total_counts = log10(total_counts + 1),
detection_rate = detected_cells / ncol(counts)
) %>%
slice_head(n = 10)
分组汇总可以用在 marker 基因上。例如按基因统计非零表达细胞比例:
marker_summary <- marker_long %>%
group_by(gene) %>%
summarise(
mean_log_counts = mean(log_counts),
expressing_cells = sum(counts > 0),
expressing_rate = expressing_cells / n(),
.groups = "drop"
) %>%
arrange(desc(expressing_rate))
在真实项目中,大部分绘图问题都先是数据整理问题。图画不好,常常不是 ggplot2 不会用,而是表格没有整理成合适的长格式。
ggplot2 的核心思想
ggplot2 使用"图形语法"。你可以把一张图理解成几层:
- data:使用哪个数据框
- aes:哪些列映射到 x、y、颜色、形状、大小
- geom:用什么几何对象展示数据
- scale:坐标轴和颜色如何转换
- theme:图的外观
- labs:标题、坐标轴和图例文字
最小示例:
ggplot(top_genes, aes(x = reorder(gene, total_counts), y = total_counts)) +
geom_col(fill = "#0f766e") +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(x = NULL, y = "Total UMI counts") +
theme_classic()

图 1:柱状图展示 PBMC 3k 中总 UMI 数最高的一组真实基因。这里过滤了线粒体和核糖体基因,避免它们占据整个图。
生信常用图表
散点图:看两个变量的关系
ggplot(qc, aes(x = nCount_RNA, y = nFeature_RNA, color = percent_mt)) +
geom_point(alpha = 0.7, size = 1.2) +
scale_x_continuous(labels = comma) +
scale_y_continuous(labels = comma) +
scale_color_gradient(low = "#0f766e", high = "#dc2626") +
labs(
x = "Total UMI counts",
y = "Detected genes",
color = "Mitochondrial %"
) +
theme_classic()

图 2:每个点是一个真实细胞条形码。散点图适合观察总 UMI 数、检测基因数和线粒体比例之间的关系。
箱线图:比较分组分布
box_data <- marker_long %>%
filter(gene %in% marker_genes[1:4])
ggplot(box_data, aes(x = gene, y = log_counts, fill = gene)) +
geom_boxplot(width = 0.6, outlier.shape = NA, alpha = 0.82) +
labs(x = NULL, y = "log1p(UMI counts)") +
theme_classic() +
theme(legend.position = "none")

图 3:箱线图展示真实 PBMC marker 基因在全部细胞中的表达分布。单细胞数据里零值很多,所以图注必须说明归一化或转换方式。
直方图:看整体分布
ggplot(qc, aes(x = nCount_RNA)) +
geom_histogram(bins = 55, fill = "#2563eb", color = "white") +
geom_vline(xintercept = median(qc$nCount_RNA), linetype = "dashed", color = "#f59e0b") +
scale_x_continuous(labels = comma) +
labs(x = "Total UMI counts per cell", y = "Number of cells") +
theme_classic()

图 4:直方图适合观察真实测序计数、基因表达、QC 指标等连续变量的分布。
小提琴图:看分布形状
ggplot(box_data, aes(x = gene, y = log_counts, fill = gene)) +
geom_violin(trim = FALSE, alpha = 0.72) +
geom_boxplot(width = 0.12, fill = "white", outlier.shape = NA) +
labs(x = NULL, y = "log1p(UMI counts)") +
theme_classic() +
theme(legend.position = "none")

图 5:小提琴图适合展示大量细胞的分布形状。单细胞表达图常用小提琴图,但要注意零值、归一化方式和细胞类型混合带来的解释边界。
分面图:同时比较多个基因或分组
facet_data <- marker_long %>%
filter(gene %in% marker_genes[1:6])
ggplot(facet_data, aes(x = log_counts)) +
geom_histogram(bins = 35, fill = "#0f766e", color = "white") +
facet_wrap(~ gene, scales = "free_y", ncol = 3) +
labs(x = "log1p(UMI counts)", y = "Cells") +
theme_bw()

图 6:分面图适合在同一套样式下比较多个真实基因。这里每个小面板都是一个 marker 基因在 PBMC 3k 细胞中的表达分布。
一个小型表达分析流程
下面用 PBMC 3k 的真实 marker 基因演示从矩阵到长表、再到可视化的完整流程。
marker_expression <- counts[marker_genes, , drop = FALSE]
gene_long <- as.data.frame(as.matrix(marker_expression)) %>%
tibble::rownames_to_column("gene") %>%
pivot_longer(
cols = -gene,
names_to = "cell",
values_to = "counts"
) %>%
mutate(log_counts = log1p(counts))
可视化表达分布:
ggplot(gene_long, aes(x = gene, y = log_counts, fill = gene)) +
geom_violin(trim = FALSE, alpha = 0.72) +
geom_boxplot(width = 0.1, fill = "white", outlier.shape = NA) +
labs(x = NULL, y = "log1p(UMI counts)") +
theme_classic() +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 30, hjust = 1)
)

图 7:表达量分布图可以快速检查不同 marker 基因的稀疏性和表达范围。它不是差异分析结果,不能直接推断细胞类型比例或显著性。
基因检出、丰度和热图
火山图通常需要两类信息:
- x 轴:log2 fold change
- y 轴:显著性,例如
-log10(adjusted p-value)
PBMC 3k 这一章还没有建立分组差异分析模型,所以这里不画"正式火山图"。如果没有真实分组、真实 log2FC 和校正后的 p 值,就不要把图包装成火山图。我们改用真实基因层面的检出细胞数和总 UMI 数,观察哪些 marker 基因在矩阵中更常被检测到。
gene_detection <- gene_summary %>%
filter(detected_cells > 0) %>%
mutate(marker = if_else(gene %in% marker_genes, "Marker gene", "Other gene"))
ggplot(gene_detection, aes(x = detected_cells, y = total_counts, color = marker)) +
geom_point(alpha = 0.45, size = 1) +
scale_x_log10(labels = comma) +
scale_y_log10(labels = comma) +
labs(
x = "Cells with detected expression",
y = "Total UMI counts",
color = NULL
) +
theme_classic()

图 8:这不是火山图,而是 PBMC 3k 真实基因的"检出细胞数 vs 总 UMI 数"散点图。它保留了原文件名以兼容网站旧链接。
热图适合展示一组基因在多个样本或细胞中的模式。常见注意点:
- 是否按行标准化
- 是否显示聚类
- 是否展示样本分组注释
- 颜色是否有清晰含义
- 基因数量是否过多

图 9:热图展示 PBMC 3k marker 基因在一组真实细胞中的表达模式。热图适合展示模式,而不是替代统计检验。
保存图片
建议所有图都显式保存,避免只留在 Notebook 或 RStudio 窗口里。
ggsave(
filename = "results/figures/pbmc3k_marker_distribution.png",
width = 7,
height = 5,
dpi = 300
)
保存前确认:
- 图片尺寸是否适合论文或网页
- 字体是否清晰
- 坐标轴是否有单位
- 图例是否能解释颜色
- 文件名是否能看出内容
AI 辅助改图
AI 可以帮你把"能画出来的图"改成"更清楚的图":检查坐标轴、图例、颜色和图注,或者把宽表改成适合 ggplot2 的长表。具体提示词和安全边界详见 AI 辅助编程与智能体工具。
但下面这些事情必须自己判断:
- 用箱线图还是小提琴图是否符合数据量
- 是否应该展示每个细胞点,还是用分布图避免过度拥挤
- 是否需要多重检验校正
- 是否能从图上得出生物学结论
- 图注是否准确描述了数据处理方式
常见坑
坑 1:宽表直接喂 ggplot
新手最常见的报错。手里一份"基因 × 样本"宽表,想画图直接 ggplot(data, aes(...)),发现 ggplot 不认。
避免:ggplot2 要长表(long format),用 tidyr::pivot_longer() 把宽表转成长表再画。
wide <- data.frame(gene = c("A","B"), s1 = 5, s2 = 10)
long <- tidyr::pivot_longer(wide, cols = -gene,
names_to = "sample", values_to = "expr")
坑 2:对数轴上展示包含 0 的数据
UMI counts 包含大量 0,直接 scale_y_log10() 会把 0 的样本静默扔掉。看图以为没 0 值,其实是被 ggplot 滤掉了。
避免:先做 log1p()(log(x+1))转换再画,或显式把 0 替换成一个小值并加图注说明。
坑 3:颜色映射用了连续变量但其实是分类
把"分组"列存成数字(1, 2, 3)而不是 factor,ggplot 会用渐变色画,逻辑混乱。
避免:分类变量明确转 factor — data$group <- factor(data$group)。
坑 4:图保存出来文字模糊
直接 ggsave("plot.png") 默认 dpi=300 但宽高没指定,画出来字小到看不清。
避免:每次保存都明确 width = 7, height = 5, dpi = 300,论文用图至少 600 dpi。
坑 5:用 RColorBrewer 时类别超过调色板上限
scale_color_brewer(palette = "Set1") 最多 9 色,画 12 个细胞类型就报 warning,部分类别会变灰。
避免:超过 9 类时用 scale_color_manual() + 自己定义颜色,或用 ggsci / viridis 包的扩展调色板。
下载资源
下一步
基础入门到这里告一段落 — 接下来是用真实流程练习。
接着深入:
- 单细胞实践 01:实践数据集与数据获取 — 把本篇练的 R + ggplot2 用在真实单细胞数据获取流程上
- 单细胞实践 03:质量控制、聚类与细胞类型注释 — 第一个完整的 scRNA-seq 分析,全程用 R
- bulk RNA-seq overview — 想做转录组而不是单细胞的话从这里进
横向延伸:
参考资源
07 数据与环境准备
BioF3 的每一章都配有可直接运行的 R 脚本。这一篇统一说明:每个脚本要什么数据、数据放在哪、怎么一次性装好所需的 R 包。
数据目录约定
所有脚本默认去同一个数据根目录里找数据,避免每个项目再重新下载:
~/biof3-data/
├── pbmc3k/ # 单细胞 module01~07 用
├── pbmc5k-citeseq/ # 单细胞 module07(CITE-seq 真实示例)用
└── pbmc10k-scatac/ # 单细胞 module10(scATAC-seq 真实示例)用
脚本里读这个路径的方式:
data_root <- Sys.getenv("BIOF3_DATA_DIR",
file.path(path.expand("~"), "biof3-data"))
pbmc_dir <- file.path(data_root, "pbmc3k")
怎么换位置:
BIOF3_DATA_DIR=/mnt/shared/biof3-data Rscript scripts/single-cell/sc03_qc_cluster_sci.R
echo 'export BIOF3_DATA_DIR=/mnt/shared/biof3-data' >> ~/.zshrc
数据清单
需要下载的数据
这三份数据由 10x Genomics 提供,前两份可以在笔记本上跑,scATAC 数据大一点、磁盘占用需要留意:
| 数据集 |
用在哪 |
体积 |
说明 |
| PBMC 3k |
单细胞 01 ~ 07、06 配套脚本、07 配套脚本 |
~35 MB |
10x Genomics 第一代示例,贯穿 scRNA-seq 主线 |
| PBMC 5k CITE-seq |
单细胞 07 CITE-seq 真实示例 |
~75 MB |
RNA + 32 个抗体的 TotalSeq-B panel |
| PBMC 10k scATAC v2 |
单细胞 10 scATAC-seq 真实示例 |
~200 MB |
peak matrix + singlecell.csv(不含 fragments) |
脚本会在首次运行时自动下载,之后缓存。如果想先一次性把三份都下好、之后离线跑,用下面的一键准备脚本。
用 Bioconductor 内置数据的模块
下面这些模块不需要手工下载任何数据,装好对应的 Bioconductor 包就能跑:
一键准备脚本
配套脚本 biof3_prepare_data.R 一次性完成:
- 检查 R 版本(推荐 R ≥ 4.3)
- 从 CRAN + Bioconductor 装所有脚本用到的 R 包
- 下载 PBMC 3k / 5k / 10k 三份数据到
~/biof3-data/
- 加载 SeuratData 的
stxBrain(空间转录组)
Rscript scripts/biof3_prepare_data.R
默认会把数据放在 ~/biof3-data/。换目录:
BIOF3_DATA_DIR=/mnt/shared/biof3-data Rscript scripts/biof3_prepare_data.R
脚本里每一步都是幂等的:装过的包、下过的数据不会重复下载。
R 包清单
按脚本粗分:
单细胞主线(module01~07):Seurat、SeuratObject、Matrix、ggplot2、dplyr、patchwork、RColorBrewer
单细胞专题:
- module05 轨迹:
slingshot、RColorBrewer、viridis
- module06 通讯:
CellChat(GitHub jinworks/CellChat)、patchwork
- module07 CITE-seq:
Seurat v5 及以上(用到 CreateAssay5Object)
- module08 TCR/BCR:
scRepertoire
- module09 空间:
SeuratData、stxBrain.SeuratData
- module10 scATAC:
Signac、EnsDb.Hsapiens.v86、GenomicRanges
bulk RNA-seq:DESeq2、edgeR、limma、airway、fission、bladderbatch、sva、clusterProfiler、org.Hs.eg.db、enrichplot、DOSE、ggrepel、pheatmap、EnhancedVolcano、apeglm
biof3_prepare_data.R 会把这些全部装好。如果只跑某几章,按需装对应包即可。
国内网络的注意事项
几个国内环境下常见的坑,解决办法:
1. Bioconductor 主站直连有时慢
BiocManager::install() 默认用 Bioconductor 官方源。如果下载很慢,临时手动指定镜像:
options(
repos = c(
BioCsoft = "https://bioconductor.org/packages/3.22/bioc",
BioCann = "https://bioconductor.org/packages/3.22/data/annotation",
BioCexp = "https://bioconductor.org/packages/3.22/data/experiment",
CRAN = "https://mirrors.tuna.tsinghua.edu.cn/CRAN"
),
timeout = 600
)
install.packages("DESeq2")
上面这段写死了 BioC 版本(3.22 对应 R 4.5),也是 biof3_prepare_data.R 内置的 fallback。装完之后回到默认 BiocManager 继续用。
2. CellChat 不在 CRAN / BioC
GitHub 直接装:
install.packages(c("sna", "ggnetwork", "collapse"))
if (!requireNamespace("devtools", quietly = TRUE)) install.packages("devtools")
devtools::install_github("jinworks/CellChat")
如果 devtools::install_github 连不上,从 https://codeload.github.com/jinworks/CellChat/tar.gz/HEAD 下 tarball 手动 R CMD INSTALL 也可以。
3. SeuratData 和 msigdbr 的数据服务器在海外
SeuratData::InstallData("stxBrain") 约 136 MB,从 AWS 拉,可能慢
msigdbr 26.x 起从 Zenodo 拉数据,国内直连常超时。如果 bulk03 需要 MSigDB,临时换成 clusterProfiler 自带的 GO/KEGG 富集也完全够用
目录结构总览
把上面这些合起来,一个完整的学习环境长这样:
~/biof3-data/ # 数据(脚本共用)
├── pbmc3k/
├── pbmc5k-citeseq/
└── pbmc10k-scatac/
~/BioF3/ # 代码(git clone 或者直接下脚本)
├── scripts/
│ ├── biof3_prepare_data.R
│ ├── single-cell/
│ │ ├── sc01_data_sci.R
│ │ └── ...
│ ├── bulk-rnaseq/
│ │ ├── bulk02_deseq2_sci.R
│ │ └── ...
└── static/scripts/ # 和 scripts/ 内容一致,供下载使用
~/R/x86_64-apple-darwin20/4.3/ # R 包库(自动管理)
├── Seurat/
├── DESeq2/
└── ...
数据根目录和代码根目录完全分开,数据集换机器 / 换项目都能共享。
常见问题
Q:脚本一直在下载同一份数据
A:检查 ~/biof3-data/ 目录是否存在。脚本会用 file.exists() 检测是否已下载;如果你换了路径、删了缓存,它就会重新下。
Q:磁盘不够,能不能把数据放在外置硬盘
A:可以,把外置硬盘路径写进 BIOF3_DATA_DIR 即可,脚本会跟着去找。
Q:装一个包失败,整个脚本断了
A:biof3_prepare_data.R 每装一个包都用 tryCatch 包着,失败会打印 warning 但不会中断。装完最后会报告哪些包失败。
下一步
环境装好之后,直接进真实流程:
接着深入:
- 单细胞实践 01:实践数据集与数据获取 — 用刚下好的 PBMC 3k 走第一个 scRNA-seq 流程
- bulk RNA-seq overview — 想做转录组的话从这里进,airway 数据已经装好
- 单细胞实践 03:质量控制、聚类与细胞类型注释 — 第一个完整的 scRNA-seq 分析
横向延伸:
参考资源