跳转至

宏基因组全流程 — 实战命令与代码

3. 实战命令/代码(完整流程)

以下命令基于 conda 环境,假设已安装所需工具。 数据为 Illumina PE150 测序,人肠道宏基因组样本。

3.0 环境准备

# ============================================================
# 步骤0:创建并激活conda环境
# ============================================================

# 创建宏基因组分析专用环境(建议Python 3.9+)
conda create -n metagenome python=3.9 -y

# 激活环境
conda activate metagenome

# 安装所需工具(通过bioconda渠道)
conda install -c bioconda -c conda-forge \
    fastqc multiqc fastp bowtie2 samtools \
    kraken2 bracken -y

# 验证安装
fastqc --version    # 应输出类似 FastQC v0.12.1
fastp --version     # 应输出类似 fastp 1.3.3
bowtie2 --version   # 应输出版本信息
kraken2 --version   # 应输出版本信息
samtools --version   # 应输出版本信息

3.1 项目目录结构

# ============================================================
# 步骤0.5:创建标准化的项目目录结构
# ============================================================

# 设置项目根目录(根据实际修改)
PROJECT_DIR="/path/to/project"

# 创建标准目录结构
mkdir -p ${PROJECT_DIR}/{00_rawdata,01_fastqc,02_clean,03_hostfree,04_taxonomy,05_function,06_diversity}

# 目录说明:
# 00_rawdata/   - 原始下机数据(fastq.gz + md5.txt)
# 01_fastqc/    - FastQC 和 MultiQC 质量评估报告
# 02_clean/     - fastp 质控后的 clean data
# 03_hostfree/  - 去宿主后的微生物 reads
# 04_taxonomy/  - Kraken2/Bracken 物种注释结果
# 05_function/  - 功能注释结果
# 06_diversity/ - 多样性分析结果

3.2 md5校验

# ============================================================
# 步骤1:md5校验 - 验证数据完整性
# ============================================================

# 进入原始数据目录
cd ${PROJECT_DIR}/00_rawdata

# 查看md5文件内容(通常由测序公司提供)
# 格式示例:d41d8cd98f00b204e9800998ecf8427e  sample1_R1.fq.gz
cat md5.txt

# 方法1:使用 -c 参数自动比对(推荐)
# -c 表示 check 模式,自动读取md5.txt中的校验值并逐一比对
md5sum -c md5.txt

# 输出示例:
# sample1_R1.fq.gz: OK
# sample1_R2.fq.gz: OK
# sample2_R1.fq.gz: OK
# sample2_R2.fq.gz: OK
# 如果出现 FAILED,说明该文件损坏,需要重新下载

# 方法2:手动计算并比对(不推荐,了解原理即可)
md5sum sample1_R1.fq.gz
# 输出的md5值与md5.txt中对应行比较

# 统计校验结果
md5sum -c md5.txt 2>&1 | grep -c "OK"      # 通过的文件数
md5sum -c md5.txt 2>&1 | grep -c "FAILED"   # 失败的文件数

3.3 质量评估(FastQC + MultiQC)

# ============================================================
# 步骤2:质量评估 - 评估原始数据质量
# ============================================================

# --- 2a. 对原始数据运行 FastQC ---

# -t 8:使用8个线程并行处理(根据服务器配置调整)
# -o:指定输出目录
# 00_rawdata/*.fq.gz:对所有fastq.gz文件运行
fastqc -t 8 \
    -o ${PROJECT_DIR}/01_fastqc/ \
    ${PROJECT_DIR}/00_rawdata/*.fq.gz

# FastQC 会为每个文件生成两个结果文件:
# sample1_R1_fastqc.html  - 可视化报告(浏览器打开)
# sample1_R1_fastqc.zip   - 原始数据(供MultiQC使用)

# --- 2b. 用 MultiQC 汇总所有 FastQC 报告 ---

# 将所有样本的FastQC结果整合为一个交互式网页
multiqc ${PROJECT_DIR}/01_fastqc/ \
    -o ${PROJECT_DIR}/01_fastqc/multiqc_report \
    -n raw_data_multiqc       # 报告名称

# 打开 raw_data_multiqc.html 查看汇总结果
# 重点关注:
# 1. 各样本的 Q20/Q30 比例
# 2. 接头含量(Adapter Content)
# 3. GC 分布是否正常
# 4. 是否有过多的重复序列

3.4 质量控制(fastp)

# ============================================================
# 步骤3:质量控制 - fastp 清洗数据
# ============================================================

# --- 单个样本处理示例 ---

SAMPLE="sample1"

fastp \
    -i ${PROJECT_DIR}/00_rawdata/${SAMPLE}_R1.fq.gz \
    -I ${PROJECT_DIR}/00_rawdata/${SAMPLE}_R2.fq.gz \
    -o ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R1.fq.gz \
    -O ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R2.fq.gz \
    --detect_adapter_for_pe \
    --qualified_quality_phred 20 \
    --unqualified_percent_limit 40 \
    --length_required 50 \
    --n_base_limit 5 \
    --cut_front \
    --cut_tail \
    --cut_window_size 4 \
    --cut_mean_quality 20 \
    --correction \
    --thread 8 \
    --json ${PROJECT_DIR}/02_clean/${SAMPLE}_fastp.json \
    --html ${PROJECT_DIR}/02_clean/${SAMPLE}_fastp.html

# 参数详解:
# -i / -I                     : 输入的R1和R2文件(大写I对应R2)
# -o / -O                     : 输出的R1和R2文件(大写O对应R2)
# --detect_adapter_for_pe     : 自动检测PE数据的接头序列并去除
# --qualified_quality_phred 20: 质量值低于20(即错误率>1%)的碱基被视为"不合格"
# --unqualified_percent_limit 40: 一条read中不合格碱基超过40%就丢弃该read
# --length_required 50        : 处理后长度<50bp的read被丢弃
#   # 纯质控场景50可接受;若下游使用 MetaPhlAn/Bracken,建议设为 70 以上
# --n_base_limit 5            : 含N碱基超过5个的read被丢弃
# --cut_front                 : 从5'端开始滑窗,遇到低质量区域则切除
# --cut_tail                  : 从3'端开始滑窗,遇到低质量区域则切除
# --cut_window_size 4         : 滑窗大小为4个碱基
# --cut_mean_quality 20       : 滑窗内平均质量低于20则切除该窗口
# --correction                : 对PE reads重叠区域进行碱基校正
# --thread 8                  : 使用8个线程
# --json / --html             : 输出fastp自带的质量报告

# --- 批量处理所有样本(推荐) ---

# 假设样本名列表文件 samples.txt,每行一个样本名
# sample1
# sample2
# sample3

for SAMPLE in $(cat ${PROJECT_DIR}/samples.txt); do
    echo "Processing: ${SAMPLE}"
    fastp \
        -i ${PROJECT_DIR}/00_rawdata/${SAMPLE}_R1.fq.gz \
        -I ${PROJECT_DIR}/00_rawdata/${SAMPLE}_R2.fq.gz \
        -o ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R1.fq.gz \
        -O ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R2.fq.gz \
        --detect_adapter_for_pe \
        --qualified_quality_phred 20 \
        --unqualified_percent_limit 40 \
        --length_required 50 \
        --n_base_limit 5 \
        --cut_front \
        --cut_tail \
        --cut_window_size 4 \
        --cut_mean_quality 20 \
        --correction \
        --thread 8 \
        --json ${PROJECT_DIR}/02_clean/${SAMPLE}_fastp.json \
        --html ${PROJECT_DIR}/02_clean/${SAMPLE}_fastp.html
    echo "${SAMPLE} done."
done

# --- 质控后再次运行 FastQC 比较效果 ---
mkdir -p ${PROJECT_DIR}/01_fastqc/clean
fastqc -t 8 \
    -o ${PROJECT_DIR}/01_fastqc/clean/ \
    ${PROJECT_DIR}/02_clean/*_clean_R*.fq.gz

multiqc ${PROJECT_DIR}/01_fastqc/clean/ \
    -o ${PROJECT_DIR}/01_fastqc/clean/multiqc_report \
    -n clean_data_multiqc

3.5 去宿主(Bowtie2)

# ============================================================
# 步骤4:去宿主 - 去除人源序列
# ============================================================

# --- 4a. 下载人类参考基因组(只需做一次) ---

# 下载 GRCh38(hg38)参考基因组
# 方法1:从NCBI下载
# wget https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/000/001/405/GCA_000001405.15_GRCh38/seqs_for_alignment_pipelines.ucsc_ids/GCA_000001405.15_GRCh38_no_alt_analysis_set.fna.gz

# 存放位置(根据实际修改)
HOST_DB="/path/to/host_db"
mkdir -p ${HOST_DB}

# 解压
# gunzip GCA_000001405.15_GRCh38_no_alt_analysis_set.fna.gz

# --- 4b. 建立 Bowtie2 索引(只需做一次,耗时约1-2小时) ---

# bowtie2-build 参数:
# 第一个参数:参考基因组fasta文件
# 第二个参数:索引前缀名
# --threads:线程数
bowtie2-build \
    --threads 16 \
    ${HOST_DB}/GRCh38.fna \
    ${HOST_DB}/GRCh38

# 建索引后会生成6个文件:
# GRCh38.1.bt2, GRCh38.2.bt2, GRCh38.3.bt2,
# GRCh38.4.bt2, GRCh38.rev.1.bt2, GRCh38.rev.2.bt2

# --- 4c. 比对去宿主 ---

SAMPLE="sample1"

# 第一步:将 clean reads 比对到人类基因组
# --very-sensitive:最灵敏模式,尽可能找到所有人源reads
# -p 16:使用16个线程
# -x:Bowtie2索引前缀
# -1 / -2:PE数据的R1和R2
# -S:输出SAM文件(后续转为BAM)
bowtie2 \
    --very-sensitive \
    -p 16 \
    -x ${HOST_DB}/GRCh38 \
    -1 ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R1.fq.gz \
    -2 ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R2.fq.gz \
    -S ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.sam \
    2> ${PROJECT_DIR}/03_hostfree/${SAMPLE}_bowtie2.log

# Bowtie2运行日志示例:
# 10000000 reads; of these:
#   10000000 (100.00%) were paired; of these:
#     2000000 (20.00%) aligned concordantly 0 times  ← 未比对上(微生物reads)
#     7500000 (75.00%) aligned concordantly exactly 1 time  ← 比对上宿主
#     500000 (5.00%) aligned concordantly >1 times
# 80.00% overall alignment rate  ← 宿主比例

# 第二步:SAM 转 BAM(压缩存储)
# -b:输出BAM格式
# -S:输入是SAM格式(较新版samtools可省略)
# -@:线程数
samtools view -bS \
    -@ 8 \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.sam \
    -o ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.bam

# 第三步:提取未比对上宿主的reads(即微生物reads)
# -b:输出BAM格式
# -f 12:只保留 flag 包含 12 的 reads(read本身和mate都未比对上)
# -F 256:排除次要比对(secondary alignment)
samtools view -b \
    -f 12 \
    -F 256 \
    -@ 8 \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.bam \
    -o ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped.bam

# 第四步:BAM排序(按read名排序,便于后续提取PE reads)
# -n:按read名排序(不是按坐标)
samtools sort -n \
    -@ 8 \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped.bam \
    -o ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped_sorted.bam

# 第五步:将BAM转回FASTQ(分别输出R1和R2)
# -1:输出R1 reads
# -2:输出R2 reads
# -0:输出单端reads(通常很少)
# -s:输出singleton reads
# -n:保持read名中的 /1 /2 标识
samtools fastq \
    -@ 8 \
    -1 ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R1.fq.gz \
    -2 ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R2.fq.gz \
    -0 /dev/null \
    -s /dev/null \
    -n \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped_sorted.bam

# 第六步:清理中间文件(节省磁盘空间)
rm -f ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.sam
rm -f ${PROJECT_DIR}/03_hostfree/${SAMPLE}_mapped.bam
rm -f ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped.bam
rm -f ${PROJECT_DIR}/03_hostfree/${SAMPLE}_unmapped_sorted.bam

# --- 4d. 统计去宿主效果 ---

# 统计 clean reads 数
echo "Clean reads (R1):"
zcat ${PROJECT_DIR}/02_clean/${SAMPLE}_clean_R1.fq.gz | wc -l | awk '{print $1/4}'

# 统计去宿主后 reads 数
echo "Host-free reads (R1):"
zcat ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R1.fq.gz | wc -l | awk '{print $1/4}'

# 计算保留率(人肠道样本通常保留70-99%)

3.6 物种注释(Kraken2 + Bracken)

# ============================================================
# 步骤5:物种注释 - Kraken2 + Bracken
# ============================================================

# --- 5a. 准备 Kraken2 数据库(只需做一次) ---

# 数据库存放路径(根据实际修改)
KRAKEN2_DB="/path/to/kraken2_db/standard"

# 方法1:下载预建数据库(推荐,节省时间)
# 常用下载源:https://benlangmead.github.io/aws-indexes/k2
# wget https://genome-idx.s3.amazonaws.com/kraken/k2_standard_20230605.tar.gz
# tar -xzf k2_standard_20230605.tar.gz -C ${KRAKEN2_DB}

# 方法2:自己构建(耗时较长,需要大内存)
# kraken2-build --standard --db ${KRAKEN2_DB} --threads 16

# --- 5b. 运行 Kraken2 ---

SAMPLE="sample1"

kraken2 \
    --db ${KRAKEN2_DB} \
    --threads 16 \
    --confidence 0.05 \
    --paired \
    --gzip-compressed \
    --output ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.output \
    --report ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.report \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R1.fq.gz \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R2.fq.gz

# 参数详解:
# --db             : Kraken2数据库路径
# --threads 16     : 使用16个线程
# --confidence 0.05: 置信度阈值,支持该分类的k-mer比例需>=5%
# --paired         : 输入是双端测序数据
# --gzip-compressed: 输入文件是gzip压缩的
# --output         : 逐条read的分类结果(很大,通常不用保留)
# --report         : 汇总分类报告(重要!后续分析用这个)

# --- Kraken2 report 格式说明 ---
# 列1: 该分类单元下reads占总reads的百分比
# 列2: 该分类单元下reads数(含子节点)
# 列3: 直接分到该分类单元的reads数
# 列4: 分类等级代码(D/P/C/O/F/G/S等)
# 列5: NCBI Taxonomy ID
# 列6: 物种学名

# --- 5c. 运行 Bracken(丰度重估计) ---

# Bracken 在 Kraken2 结果基础上,将高层级reads重分配到种水平
bracken \
    -d ${KRAKEN2_DB} \
    -i ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.report \
    -o ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_bracken_S.tsv \
    -w ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_bracken_S.report \
    -r 150 \
    -l S \
    -t 10

# 参数详解:
# -d : Kraken2数据库路径(Bracken使用同一个数据库)
# -i : Kraken2的report文件
# -o : Bracken输出的丰度表(TSV格式)
# -w : Bracken生成的新report文件
# -r 150 : read长度(必须与实际一致,PE150就写150)
# -l S   : 分析层级,S表示种(Species)
# -t 10  : 最小reads阈值,低于10条reads的物种被过滤

# 也可以生成属水平丰度
bracken \
    -d ${KRAKEN2_DB} \
    -i ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.report \
    -o ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_bracken_G.tsv \
    -w ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_bracken_G.report \
    -r 150 \
    -l G \
    -t 10

# --- 5d. 查看结果 ---

# 查看Bracken种水平丰度表
# 列:name, taxonomy_id, taxonomy_lvl, kraken_assigned_reads, added_reads, new_est_reads, fraction_total_reads
head -20 ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_bracken_S.tsv

# 查看分类统计
echo "=== Classification Summary ==="
grep -c "C" ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.output   # 已分类reads数
grep -c "U" ${PROJECT_DIR}/04_taxonomy/${SAMPLE}_kraken2.output   # 未分类reads数

3.7 功能注释(HUMAnN3 简要)

# ============================================================
# 步骤6:功能注释 - HUMAnN3(简要示例)
# ============================================================

# --- 安装 HUMAnN3(在单独的conda环境中,避免依赖冲突) ---
# conda create -n humann3 python=3.9 -y
# conda activate humann3
# pip install humann

# --- 下载数据库(首次使用时下载) ---
# humann_databases --download chocophlan full /path/to/humann_db --update-config yes
# humann_databases --download uniref uniref90_diamond /path/to/humann_db --update-config yes

# --- 运行 HUMAnN3 ---

SAMPLE="sample1"

# HUMAnN3 接受合并的PE reads文件
# 先合并R1和R2(cat拼接,HUMAnN3内部处理)
cat ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R1.fq.gz \
    ${PROJECT_DIR}/03_hostfree/${SAMPLE}_hostfree_R2.fq.gz \
    > ${PROJECT_DIR}/05_function/${SAMPLE}_merged.fq.gz

# 运行HUMAnN3
humann \
    --input ${PROJECT_DIR}/05_function/${SAMPLE}_merged.fq.gz \
    --output ${PROJECT_DIR}/05_function/${SAMPLE}_humann3/ \
    --threads 16

# 主要输出文件:
# ${SAMPLE}_genefamilies.tsv    - 基因家族丰度(RPK)
# ${SAMPLE}_pathabundance.tsv   - 代谢通路丰度
# ${SAMPLE}_pathcoverage.tsv    - 通路覆盖度

# --- 结果标准化 ---

# 将丰度标准化为 CPM(copies per million)
humann_renorm_table \
    --input ${PROJECT_DIR}/05_function/${SAMPLE}_humann3/${SAMPLE}_merged_genefamilies.tsv \
    --output ${PROJECT_DIR}/05_function/${SAMPLE}_genefamilies_cpm.tsv \
    --units cpm

humann_renorm_table \
    --input ${PROJECT_DIR}/05_function/${SAMPLE}_humann3/${SAMPLE}_merged_pathabundance.tsv \
    --output ${PROJECT_DIR}/05_function/${SAMPLE}_pathabundance_cpm.tsv \
    --units cpm

# --- 合并多个样本的结果 ---
# humann_join_tables -i ${PROJECT_DIR}/05_function/ -o merged_genefamilies.tsv --file_name genefamilies_cpm

3.8 多样性分析(R脚本示例)

# ============================================================
# 步骤7:多样性分析 - 基于R(示例代码)
# ============================================================

# 在R环境中运行以下脚本
# 需要安装:vegan, ggplot2, dplyr, ape 等包
# ============================================================
# R脚本:宏基因组多样性分析
# ============================================================

# --- 加载R包 ---
library(vegan)     # 生态学多样性分析核心包
library(ggplot2)   # 画图
library(dplyr)     # 数据处理
library(ape)       # 进化分析(PCoA用)

# --- 读取丰度表 ---
# 假设已将所有样本的Bracken种水平丰度合并为一个矩阵
# 行=物种,列=样本,值=reads数
abundance <- read.csv("species_abundance_matrix.csv", row.names = 1)

# 转置为样本在行、物种在列的格式(vegan要求)
abundance_t <- t(abundance)

# --- Alpha多样性 ---

# 计算Shannon指数
shannon <- diversity(abundance_t, index = "shannon")

# 计算Simpson指数
simpson <- diversity(abundance_t, index = "simpson")

# 计算观测到的物种数(richness)
richness <- specnumber(abundance_t)

# 计算Pielou均匀度(Shannon / ln(物种数))
pielou <- shannon / log(richness)

# 汇总Alpha多样性结果
alpha_div <- data.frame(
    Sample = rownames(abundance_t),
    Shannon = round(shannon, 3),
    Simpson = round(simpson, 3),
    Richness = richness,
    Pielou = round(pielou, 3)
)
print(alpha_div)

# 写出结果
write.csv(alpha_div, "alpha_diversity.csv", row.names = FALSE)

# --- Alpha多样性箱线图 ---
# 假设有分组信息
# group_info <- read.csv("group_info.csv")  # 列:Sample, Group
# alpha_div <- merge(alpha_div, group_info, by = "Sample")
#
# ggplot(alpha_div, aes(x = Group, y = Shannon, fill = Group)) +
#     geom_boxplot() +
#     theme_minimal() +
#     labs(title = "Shannon Diversity", y = "Shannon Index")

# --- Beta多样性 ---

# 计算Bray-Curtis距离矩阵
bray_dist <- vegdist(abundance_t, method = "bray")

# PCoA分析(主坐标分析)
pcoa_result <- pcoa(bray_dist)

# 提取前两个主坐标轴
pcoa_df <- data.frame(
    Sample = rownames(pcoa_result$vectors),
    PC1 = pcoa_result$vectors[, 1],
    PC2 = pcoa_result$vectors[, 2]
)

# 计算各轴解释的变异比例
var_explained <- pcoa_result$values$Relative_eig * 100

# PCoA可视化
# pcoa_df <- merge(pcoa_df, group_info, by = "Sample")
#
# ggplot(pcoa_df, aes(x = PC1, y = PC2, color = Group)) +
#     geom_point(size = 3) +
#     stat_ellipse(level = 0.95) +
#     theme_minimal() +
#     labs(
#         title = "PCoA (Bray-Curtis)",
#         x = paste0("PC1 (", round(var_explained[1], 1), "%)"),
#         y = paste0("PC2 (", round(var_explained[2], 1), "%)")
#     )

# --- PERMANOVA 统计检验 ---
# 检验不同分组间的Beta多样性是否有显著差异
# group_info <- read.csv("group_info.csv")
# permanova_result <- adonis2(bray_dist ~ Group, data = group_info, permutations = 999)
# print(permanova_result)
# p值 < 0.05 表示组间差异显著