第11期 ⭐⭐ 进阶

差异表达分析

用PyDESeq2进行RNA-seq差异分析,火山图、热图、基因注释一键生成

学习时间: 约30分钟 难度: 进阶
⚠️
免责声明: 本内容仅供医学学习参考,不作为临床诊断依据。 实际临床决策请结合患者具体情况和多学科意见。 所有品牌名称已被通用化处理。
🎯

技能简介

RNA-seq差异表达分析是转录组研究的核心方法。传统方式学习R语言的DESeq2需要1周时间, 使用Python版本的PyDESeq2,30分钟即可完成从数据加载到可视化、基因注释的全流程。

本教程将使用两大工具:PyDESeq2(差异分析)、gget(基因信息查询), 教你快速完成RNA-seq差异分析。

🧬 PyDESeq2 🔍 gget

💡 使用场景

🧬

药物处理研究

比较药物处理组和对照组的基因表达差异,发现药物作用机制

🔬

疾病vs健康对照

鉴定疾病相关基因,寻找潜在生物标志物

⏱️

时间序列分析

分析不同时间点的基因表达变化,追踪动态调控过程

🌱

基因敲除/过表达

评估基因操作对全基因组表达的影响

📊

论文图表生成

火山图、MA图、热图、PCA图等论文必备图表一键生成

🔗

基因功能注释

快速查询差异基因的功能描述、GO注释、相关疾病

🛠️ 核心技能调用

# 技能1: PyDESeq2 - Python版差异表达分析
from pydeseq2 import DESeq2
from pydeseq2.utils import load_example_data

# 创建DESeq2对象
dds = DESeq2(counts=count_matrix, design_factors=~condition)

# 运行差异分析
dds.run_deseq()

# 获取结果
results = dds.results_df
# 技能2: gget - 基因信息快速查询
import gget

# 查询基因信息
gene_info = gget.info("TP53")

# 查询GO注释
go_terms = gget.go("TP53")

# 查询相关疾病
diseases = gget.disease("TP53")
# 技能3: 可视化 - 火山图与热图
import matplotlib.pyplot as plt
import seaborn as sns

# 火山图
plt.figure(figsize=(8, 6))
sns.scatterplot(data=results, x='log2FoldChange', y='-np.log10(padj)')

# 热图
sns.clustermap(top_genes_data, cmap='coolwarm')

📖 实战示例:RNA-seq差异表达分析

Step 1: 数据加载

加载RNA-seq计数矩阵和样本信息:

import pandas as pd
import numpy as np
from pydeseq2 import DESeq2
from pydeseq2.preprocessing import deseq2_norm

# 加载计数矩阵
counts_df = pd.read_csv('count_matrix.csv', index_col=0)

# 加载样本信息
sample_info = pd.DataFrame({
    'condition': ['control']*5 + ['treated']*5  # 对照组(n=5) + 处理组(n=5)
}, index=counts_df.columns)

# 查看数据维度
print(f"基因数: {counts_df.shape[0]}")
print(f"样本数: {counts_df.shape[1]}")

# 预过滤:去除低表达基因
keep = (counts_df >= 10).sum(axis=1) >= 3
counts_filtered = counts_df[keep]

print(f"过滤后基因数: {counts_filtered.shape[0]}")

💡 数据要求

  • • 计数矩阵应为原始read count,未标准化的数据
  • • 行为基因,列为样本
  • • 样本信息需包含分组信息(如control vs treated)
  • • 建议每组至少3个生物学重复
Step 2: 差异表达分析

使用PyDESeq2进行完整的差异表达分析流程:

# 创建DESeq2对象
dds = DESeq2(
    counts=counts_filtered,
    design_factors=sample_info,
    design_formula="~ condition"
)

# 运行DESeq2流程
# 包括:size factor估计、离散度估计、Wald检验
dds.run_deseq()

# 获取结果
res = dds.results_df

# 筛选显著差异基因
sig_genes = res[
    (res['padj'] < 0.05) &      # BH校正p值 < 0.05
    (abs(res['log2FoldChange']) > 1)  # |log2FC| > 1
]

print(f"发现 {len(sig_genes)} 个显著差异基因")
print(sig_genes.head(10))

📌 DESeq2流程说明

  • Size Factor标准化:median of ratios方法,校正测序深度差异
  • 离散度估计:估计基因表达的变异程度
  • 负二项分布建模:适合count数据的统计模型
  • Wald检验:检验log2 fold change是否显著异于0
  • BH校正:Benjamini-Hochberg方法控制假阳性率
Step 3: 可视化分析

生成差异分析的标准可视化图表:

import matplotlib.pyplot as plt
import seaborn as sns

# 1. 火山图
fig, ax = plt.subplots(figsize=(10, 6))

# 标记显著基因
res['significant'] = (res['padj'] < 0.05) & (abs(res['log2FoldChange']) > 1)

# 绘制散点
sns.scatterplot(
    data=res,
    x='log2FoldChange',
    y='-np.log10(padj)',
    hue='significant',
    palette={False: 'gray', True: '#8B5CF6'},
    ax=ax
)

# 标注top 10基因
top_genes = sig_genes.nsmallest(10, 'padj')
for _, gene in top_genes.iterrows():
    ax.annotate(gene.name, (gene['log2FoldChange'], -np.log10(gene['padj'])))

ax.set_xlabel('Log2 Fold Change')
ax.set_ylabel('-Log10(Adjusted P-value)')
ax.set_title('Volcano Plot')
plt.savefig('volcano_plot.png', dpi=300, bbox_inches='tight')

# 2. MA图
fig, ax = plt.subplots(figsize=(10, 6))
sns.scatterplot(
    data=res,
    x='baseMean',
    y='log2FoldChange',
    hue='significant',
    palette={False: 'gray', True: '#8B5CF6'},
    ax=ax
)
ax.axhline(y=0, color='red', linestyle='--')
ax.set_xlabel('Mean of Normalized Counts')
ax.set_ylabel('Log2 Fold Change')
ax.set_title('MA Plot')
plt.savefig('ma_plot.png', dpi=300, bbox_inches='tight')

# 3. PCA图(样本聚类)
normalized_counts = dds.normalized_counts
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pca_result = pca.fit_transform(normalized_counts.T)

fig, ax = plt.subplots(figsize=(8, 6))
sns.scatterplot(
    x=pca_result[:, 0],
    y=pca_result[:, 1],
    hue=sample_info['condition'],
    palette={'control': '#3B82F6', 'treated': '#8B5CF6'},
    ax=ax
)
ax.set_xlabel('PC1')
ax.set_ylabel('PC2')
ax.set_title('PCA Plot')
plt.savefig('pca_plot.png', dpi=300, bbox_inches='tight')

print("可视化图表已保存!")
Step 4: 差异基因热图

生成top差异基因的表达热图:

import seaborn as sns

# 选择top 50差异基因
top50_genes = sig_genes.nsmallest(50, 'padj').index

# 提取标准化表达值
heatmap_data = dds.normalized_counts.loc[top50_genes]

# z-score标准化
heatmap_data_z = (heatmap_data - heatmap_data.mean(axis=1).values.reshape(-1)) / heatmap_data.std(axis=1).values.reshape(-1)

# 绘制热图
g = sns.clustermap(
    heatmap_data_z,
    cmap='coolwarm',
    center=0,
    figsize=(12, 10),
    row_cluster=True,
    col_cluster=True,
    cbar_kws={'label': 'Z-score'}
)

# 添加样本分组注释
col_colors = sample_info['condition'].map({'control': '#3B82F6', 'treated': '#8B5CF6'})
g.ax_heatmap.set_xlabel('Samples')
g.ax_heatmap.set_ylabel('Genes')
g.ax_col_dendrogram.set_visible(False)

plt.savefig('heatmap_top50.png', dpi=300, bbox_inches='tight')
print("热图已保存!")
Step 5: 基因功能注释

使用gget查询差异基因的功能信息:

import gget

# 选择top 20差异基因进行注释
top20_genes = sig_genes.nsmallest(20, 'padj').index.tolist()

# 批量查询基因信息
gene_annotations = []
for gene in top20_genes:
    try:
        info = gget.info(gene, "ensembl")
        gene_annotations.append({
            'gene': gene,
            'full_name': info.get('name', 'N/A'),
            'description': info.get('description', 'N/A'),
            'log2FC': sig_genes.loc[gene, 'log2FoldChange'],
            'padj': sig_genes.loc[gene, 'padj']
        })
    except:
        gene_annotations.append({
            'gene': gene,
            'full_name': 'N/A',
            'description': 'N/A',
            'log2FC': sig_genes.loc[gene, 'log2FoldChange'],
            'padj': sig_genes.loc[gene, 'padj']
        })

# 创建注释数据框
annotation_df = pd.DataFrame(gene_annotations)

# 保存注释结果
annotation_df.to_csv('gene_annotations.csv', index=False)

print("Top 20差异基因注释:")
print(annotation_df.to_string())

# 查询GO注释(以某个基因为例)
top_gene = top20_genes[0]
try:
    go_result = gget.go(top_gene, "ensembl")
    print(f"\n{top_gene} GO注释:")
    print(go_result.head(10))
except:
    print("GO注释查询失败")

💡 gget支持的数据库

  • Ensembl:基因注释、序列信息
  • UniProt:蛋白质功能、结构
  • NCBI:基因参考文献
  • GO:基因本体论注释
  • KEGG:通路注释
Step 6: 结果导出

导出完整的差异分析结果:

# 导出所有基因的差异分析结果
res.to_csv('deseq2_results_all.csv', index=True)

# 导出显著差异基因
sig_genes.to_csv('deseq2_results_significant.csv', index=True)

# 导出标准化表达矩阵
dds.normalized_counts.to_csv('normalized_counts.csv')

# 生成分析报告
report = f"""
差异表达分析报告
================

样本信息:
- 对照组: {sum(sample_info['condition']=='control')} 样本
- 处理组: {sum(sample_info['condition']=='treated')} 样本

分析结果:
- 总基因数: {len(res)}
- 显著差异基因数: {len(sig_genes)}
  * 上调基因: {sum(sig_genes['log2FoldChange'] > 0)}
  * 下调基因: {sum(sig_genes['log2FoldChange'] < 0)}

筛选标准:
- |log2FC| > 1
- padj < 0.05

生成文件:
- volcano_plot.png (火山图)
- ma_plot.png (MA图)
- pca_plot.png (PCA图)
- heatmap_top50.png (热图)
- deseq2_results_all.csv (所有基因)
- deseq2_results_significant.csv (显著基因)
- gene_annotations.csv (基因注释)
"""

with open('deseq2_report.txt', 'w') as f:
    f.write(report)

print("分析完成!报告已保存。")
print(report)

⚠️ 注意事项

批次效应

如果样本来自不同批次,需要考虑批次效应校正。可以在design formula中添加batch因子(如~ batch + condition)。

样本量要求

建议每组至少3-5个生物学重复。样本量过少会降低统计功效,增加假阴性。对于小样本研究,可以考虑使用edgeR或limma-voom等更敏感的方法。

多重检验校正

差异分析涉及数万个基因的同时检验,必须进行多重检验校正。推荐使用BH方法(FDR控制),常用阈值为padj < 0.05或padj < 0.01。

log2FC阈值选择

常用阈值为|log2FC| > 1(即2倍变化)。但对于某些研究(如转录因子),较小的变化也可能有生物学意义,可以考虑降低到|log2FC| > 0.5(1.4倍)。

🔗 相关技能链接

📦

下载完整代码包

包含:示例代码、数据文件、结果图表 · 7个文件 · 1.7MB

立即下载

💡 代码包内含 README.md 文档,包含环境配置和运行说明。解压后即可使用。