非编码 RNA(ncRNA)是基因组中不编码蛋白质的 RNA 分子,其中 lncRNA(长链非编码 RNA)、circRNA(环状 RNA)及由其构成的 ceRNA(内源竞争 RNA)网络,已成为肿瘤发生发展、代谢调控、免疫应答等领域的研究热点。不同于编码基因分析,ncRNA 具有 "序列保守性低、功能机制复杂、依赖调控网络解析" 的特点,需一套从数据获取到实验验证的完整分析体系。
本文结合生信实战场景,系统拆解 lncRNA/circRNA/ceRNA 分析的全流程,涵盖数据下载与质控→预处理与定量→差异表达分析→ceRNA 网络构建→功能富集→实验验证 6 大核心环节,提供 Python、R、Shell 全套代码模板,适配 GEO、TCGA 等公共数据集及自建测序数据,助力研究者快速落地 ncRNA 相关研究。
一、分析前准备:核心概念与工具清单
在正式分析前,需明确三类 ncRNA 的核心特性及分析逻辑,避免流程偏差:
- lncRNA:长度>200nt 的线性 ncRNA,通过吸附 miRNA、调控染色质修饰等发挥作用,分析核心是 "差异表达 + 靶标预测 + 功能关联"。
- circRNA:由前体 mRNA 反向剪接形成的环状分子,稳定性高,核心功能是作为 ceRNA 吸附 miRNA,分析需重点关注 "环状结构识别 + miRNA 结合位点预测"。
- ceRNA 网络:核心逻辑是 "ceRNA(lncRNA/circRNA)与 mRNA 竞争结合同一 miRNA",通过调控 miRNA 浓度间接影响 mRNA 表达,分析核心是 "分子间相互作用验证 + 网络拓扑分析"。
必备工具与环境配置
| 分析环节 | 核心工具 | 语言 / 平台 | 核心功能 |
|---|---|---|---|
| 数据下载 | SRA Toolkit、TCGAbiolinks | Shell/R | 下载 GEO/TCGA 原始测序数据 |
| 质量控制 | FastQC、MultiQC | Shell | 评估 FASTQ 数据质量(碱基质量、接头污染) |
| 序列比对 | STAR、HISAT2 | Shell | 基因组比对,获取比对 BAM 文件 |
| 转录本组装 | StringTie、Cufflinks | Shell | 组装转录本,识别新 lncRNA/circRNA |
| 定量分析 | Salmon、FeatureCounts | Shell/R | 计算基因 / 转录本表达量(count 矩阵) |
| 差异分析 | DESeq2、edgeR、limma | R | 筛选差异表达 lncRNA/circRNA/mRNA/miRNA |
| 靶标预测 | TargetScan、miRanda、RNAhybrid | Python/R | 预测 miRNA 与 ceRNA/mRNA 的结合位点 |
| 网络构建 | Cytoscape、igraph | R/Python | 构建 ceRNA 调控网络,拓扑分析 |
| 功能富集 | clusterProfiler、clusterProfiler2 | R | GO/KEGG 富集、GSEA 分析 |
| 可视化 | ggplot2、pheatmap、ComplexHeatmap | R | 表达热图、火山图、富集气泡图 |
环境配置建议:使用 Conda 统一管理环境,避免依赖冲突
bash
# 创建 ncRNA 分析专用环境
conda create -n ncRNA_analysis python=3.8 R=4.2.0 -y
conda activate ncRNA_analysis
# 安装 Shell 工具
conda install -c bioconda fastqc multiqc star hisat2 stringtie salmon featurecounts sra-tools -y
# 安装 R 包(通过 R 终端执行)
install.packages(c("tidyverse", "pheatmap", "ggplot2"))
if (!require("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install(c("DESeq2", "edgeR", "limma", "clusterProfiler", "org.Hs.eg.db", "TCGAbiolinks"))
# 安装 Python 包
pip install pandas numpy matplotlib seaborn scipy networkx
二、第一步:数据下载与质量控制
ncRNA 分析的数据来源主要分为两类:公共数据库(GEO/TCGA/ENCODE) 和 自建测序数据(FASTQ 格式)。本节重点讲解公共数据下载流程,自建数据可直接跳过下载步骤,进入质控环节。
1. 公共数据下载(GEO/TCGA 示例)
(1)GEO 数据集下载(Shell + SRA Toolkit)
GEO 中原始测序数据以 SRA 格式存储,需用 SRA Toolkit 转换为 FASTQ 格式。示例:下载 GEO 数据集 GSE185997(lncRNA 与肺癌相关的 RNA-seq 数据)
bash
# 1. 安装 SRA Toolkit(已通过 Conda 安装可跳过)
# 2. 创建数据存储目录
mkdir -p GSE185997/{sra,fastq,qc}
cd GSE185997
# 3. 下载 SRA 文件(需先在 GEO 页面获取 SRA 访问号,如 SRR19769901、SRR19769902...)
prefetch SRR19769901 SRR19769902 SRR19769903 -O ./sra/
# 4. 转换 SRA 为 FASTQ(单端数据用 --split-3,双端数据自动拆分 R1/R2)
fastq-dump --split-3 ./sra/SRR19769901.sra -O ./fastq/
fastq-dump --split-3 ./sra/SRR19769902.sra -O ./fastq/
fastq-dump --split-3 ./sra/SRR19769903.sra -O ./fastq/
(2)TCGA 数据集下载(R + TCGAbiolinks)
TCGA 提供标准化的 RNA-seq 表达数据(HTSeq-Counts 格式),可直接下载表达矩阵,无需原始数据处理。
R
# 加载 R 包
library(TCGAbiolinks)
library(SummarizedExperiment)
library(tidyverse)
# 下载 TCGA-LUAD(肺腺癌)的 RNA-seq 数据(HTSeq-Counts 格式)
query <- GDCquery(
project = "TCGA-LUAD",
data.category = "Transcriptome Profiling",
data.type = "Gene Expression Quantification",
workflow.type = "HTSeq - Counts"
)
# 执行下载并整理数据
GDCdownload(query, directory = "./TCGA-LUAD")
tcga_data <- GDCprepare(query, directory = "./TCGA-LUAD")
# 提取表达矩阵(行:基因,列:样本)
count_matrix <- assay(tcga_data)
# 提取样本临床信息(用于分组)
sample_info <- colData(tcga_data) %>% as.data.frame() %>%
select(sample, sample_type) # sample_type 包含 Tumor/Normal 分组
2. 数据质量控制(FastQC + MultiQC)
原始测序数据可能存在接头污染、低质量碱基等问题,需通过质控筛选合格数据,避免影响后续分析。
bash
# 1. 对所有 FASTQ 文件进行质量评估
fastqc ./fastq/*.fastq -o ./qc/
# 2. 用 MultiQC 整合所有质控结果(生成可视化报告)
multiqc ./qc/ -o ./qc/ --title "GSE185997_QC_Report"
质控结果解读与处理:
- 核心指标:碱基质量值(Q20/Q30 占比≥80% 为合格)、接头污染率、序列长度分布。
- 问题处理:若存在接头污染,用 Trimmomatic 去除接头;低质量序列用
trimmomatic PE过滤:
bash
# 安装 Trimmomatic
conda install -c bioconda trimmomatic -y
# 双端数据过滤示例(去除接头+低质量碱基)
trimmomatic PE -phred33 \
./fastq/SRR19769901_1.fastq ./fastq/SRR19769901_2.fastq \
./fastq/clean_SRR19769901_1.fastq ./fastq/unpaired_SRR19769901_1.fastq \
./fastq/clean_SRR19769901_2.fastq ./fastq/unpaired_SRR19769901_2.fastq \
ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 \ # 接头文件路径
LEADING:3 TRAILING:3 SLIDINGWINDOW:4:15 MINLEN:36 # 过滤参数
三、第二步:数据预处理与定量分析
预处理核心是 "序列比对→转录本组装→表达定量",最终得到 lncRNA、circRNA、mRNA 的表达矩阵(count 或 TPM 格式),为差异分析做准备。
1. lncRNA 预处理与定量(STAR + StringTie + gffcompare)
lncRNA 定量需结合参考基因组注释,识别已知 lncRNA 并预测新 lncRNA。
bash
# 1. 下载人类参考基因组(hg38)及注释文件(GENCODE v44)
mkdir -p ./reference/hg38
cd ./reference/hg38
wget https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_44/GRCh38.p14.genome.fa.gz
wget https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_44/gencode.v44.annotation.gtf.gz
gunzip GRCh38.p14.genome.fa.gz gencode.v44.annotation.gtf.gz
# 2. 构建 STAR 索引(仅需执行一次)
STAR --runThreadN 8 \ # 线程数,根据 CPU 核心调整
--runMode genomeGenerate \
--genomeDir ./star_index \
--genomeFastaFiles GRCh38.p14.genome.fa \
--sjdbGTFfile gencode.v44.annotation.gtf \
--sjdbOverhang 100 # 与测序读长匹配(通常为读长-1)
# 3. 双端序列比对(以清洁数据为例)
STAR --runThreadN 8 \
--genomeDir ./reference/hg38/star_index \
--readFilesIn ./fastq/clean_SRR19769901_1.fastq ./fastq/clean_SRR19769901_2.fastq \
--outSAMtype BAM SortedByCoordinate \ # 输出排序后的 BAM 文件
--outFileNamePrefix ./alignment/SRR19769901_ \
--quantMode TranscriptomeSAM GeneCounts # 同时输出转录本和基因水平计数
# 4. StringTie 转录本组装(合并所有样本的组装结果)
# 4.1 单个样本组装
stringtie ./alignment/SRR19769901_Aligned.sortedByCoord.out.bam \
-p 8 -G ./reference/hg38/gencode.v44.annotation.gtf \
-o ./assembly/SRR19769901.gtf -l SRR19769901 # 转录本前缀
# 4.2 合并所有样本的 GTF 文件(生成整合转录组)
ls ./assembly/*.gtf > assembly_list.txt
stringtie --merge -p 8 -G ./reference/hg38/gencode.v44.annotation.gtf \
-o ./assembly/merged_transcripts.gtf assembly_list.txt
# 5. gffcompare 注释转录本(区分已知/新转录本)
gffcompare -r ./reference/hg38/gencode.v44.annotation.gtf \
-G -o ./annotation/merged ./assembly/merged_transcripts.gtf
# 6. 筛选 lncRNA(根据 gffcompare 结果,保留 lncRNA 类型转录本)
# 生成 lncRNA 专属 GTF 文件
awk '$3=="transcript" && $10~/"lncRNA"/ || $10~/"antisense"/ || $10~/"lincRNA"/' \
./annotation/merged.annotated.gtf > ./annotation/lncRNA_annotated.gtf
# 7. 定量 lncRNA 表达量(FeatureCounts)
featureCounts -T 8 -t transcript -g gene_id \
-a ./annotation/lncRNA_annotated.gtf \
-o ./quantification/lncRNA_counts.txt \
./alignment/*.sortedByCoord.out.bam
2. circRNA 预处理与定量(STAR + CIRI2)
circRNA 识别需专门工具(CIRI2/CIRIquant),核心是检测 "反向剪接位点" 以确认环状结构。
bash
# 1. 安装 CIRI2(已通过 Conda 安装可跳过)
conda install -c bioconda ciri2 -y
# 2. 用 STAR 比对生成 Chimeric.out.junction 文件(记录剪接位点)
STAR --runThreadN 8 \
--genomeDir ./reference/hg38/star_index \
--readFilesIn ./fastq/clean_SRR19769901_1.fastq ./fastq/clean_SRR19769901_2.fastq \
--outSAMtype BAM SortedByCoordinate \
--outFileNamePrefix ./alignment/circ_SRR19769901_ \
--chimSegmentMin 10 # 最小嵌合片段长度
# 3. CIRI2 识别 circRNA(输入 BAM 文件和剪接位点文件)
CIRI2.pl -I ./alignment/circ_SRR19769901_Aligned.sortedByCoord.out.bam \
-O ./circRNA/SRR19769901_circRNA.txt \
-F ./reference/hg38/GRCh38.p14.genome.fa \
-A ./reference/hg38/gencode.v44.annotation.gtf \
-J ./alignment/circ_SRR19769901_Chimeric.out.junction \
-T 8
# 4. 合并多个样本的 circRNA 定量结果(生成表达矩阵)
# 用 Python 脚本合并(需提前安装 pandas)
python merge_circRNA_counts.py # 脚本内容见下方
merge_circRNA_counts.py 脚本:
python
import pandas as pd
import os
# 获取所有 circRNA 结果文件
circ_files = [f for f in os.listdir("./circRNA/") if f.endswith("_circRNA.txt")]
df_list = []
for file in circ_files:
sample = file.split("_circRNA.txt")[0]
# 读取 CIRI2 输出文件(第 1 列:circRNA ID,第 7 列:表达量(junction reads))
df = pd.read_csv(f"./circRNA/{file}", sep="\t", usecols=[0, 6], names=["circRNA_ID", sample])
df_list.append(df)
# 合并所有样本(按 circRNA_ID 对齐)
merged_df = df_list[0]
for df in df_list[1:]:
merged_df = pd.merge(merged_df, df, on="circRNA_ID", how="outer").fillna(0)
# 保存 circRNA 表达矩阵(count 格式)
merged_df.to_csv("./quantification/circRNA_counts.txt", index=False, sep="\t")
3. mRNA 定量(Salmon 快速定量)
mRNA 定量可直接使用 Salmon 进行转录组水平定量,无需比对到基因组,速度更快。
bash
# 1. 构建 Salmon 索引(针对 GENCODE 转录组)
wget https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_44/gencode.v44.transcripts.fa.gz
gunzip gencode.v44.transcripts.fa.gz
salmon index -t gencode.v44.transcripts.fa -i ./reference/hg38/salmon_index -k 31
# 2. 定量(双端数据)
salmon quant -i ./reference/hg38/salmon_index \
-l A \ # 自动识别文库类型
-1 ./fastq/clean_SRR19769901_1.fastq \
-2 ./fastq/clean_SRR19769901_2.fastq \
-o ./quantification/salmon_SRR19769901 \
--validateMappings # 验证映射准确性
# 3. 合并所有样本的 mRNA 表达矩阵(TPM 格式)
salmon quantmerge -i ./quantification/salmon_* -o ./quantification/mRNA_tpm.txt --tpm
四、第三步:差异表达分析
差异分析的核心是筛选 "病例组 vs 对照组" 中表达显著变化的分子(lncRNA/circRNA/mRNA/miRNA),常用工具为 DESeq2(适用于 count 数据)、limma(适用于 TPM/FPKM 数据)。
1. 数据预处理(R 脚本)
首先整理表达矩阵和分组信息,确保样本匹配、格式正确。
R
library(tidyverse)
library(DESeq2)
library(limma)
library(pheatmap)
library(ggplot2)
# 1. 读取 lncRNA 表达矩阵(count 格式)
lncRNA_counts <- read.delim("./quantification/lncRNA_counts.txt", skip = 1, row.names = 1)
# 去除冗余列(FeatureCounts 输出的第 2-6 列为统计信息)
lncRNA_counts <- lncRNA_counts[, -c(1:5)]
# 简化列名(保留样本 ID 核心部分)
colnames(lncRNA_counts) <- gsub("alignment\\.|_Aligned.sortedByCoord.out.bam", "", colnames(lncRNA_counts))
# 2. 读取分组信息(需手动创建,格式:样本 ID + 分组(case/control))
group_info <- read.delim("./sample_group.txt", row.names = 1)
# 确保分组信息与表达矩阵样本顺序一致
lncRNA_counts <- lncRNA_counts[, rownames(group_info)]
# 3. 过滤低表达基因(保留至少在 3 个样本中表达量≥1 的基因)
keep <- rowSums(lncRNA_counts >= 1) >= 3
lncRNA_counts_filtered <- lncRNA_counts[keep, ]
2. 差异表达分析(DESeq2 示例)
适用于 count 格式数据(lncRNA、circRNA、mRNA 的 count 矩阵)
R
# 1. 构建 DESeq2 数据集
dds <- DESeqDataSetFromMatrix(
countData = lncRNA_counts_filtered,
colData = group_info,
design = ~ group # group 为分组列名(case/control)
)
# 2. 差异分析(标准化+统计检验)
dds <- DESeq(dds)
# 提取差异结果(case vs control)
res <- results(dds, contrast = c("group", "case", "control"))
# 3. 结果筛选(padj < 0.05 且 |log2FC| > 1)
res_filtered <- res %>%
as.data.frame() %>%
rownames_to_column("gene_id") %>%
filter(padj < 0.05 & abs(log2FoldChange) > 1) %>%
arrange(padj)
# 4. 保存差异结果
write.csv(res_filtered, "./differential/lncRNA_diff_expr.csv", row.names = FALSE)
# 5. 可视化:火山图
res_df <- res %>% as.data.frame() %>% rownames_to_column("gene_id")
ggplot(res_df, aes(x = log2FoldChange, y = -log10(padj))) +
geom_point(aes(color = ifelse(padj < 0.05 & abs(log2FoldChange) > 1, "显著差异", "无差异")),
alpha = 0.6, size = 1) +
scale_color_manual(values = c("red", "gray")) +
labs(x = "log2(Fold Change)", y = "-log10(Adjusted P-value)", color = "差异类型") +
theme_bw() +
geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "black") +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black")
ggsave("./plots/lncRNA_volcano.png", width = 8, height = 6, dpi = 300)
# 6. 可视化:热图(top 50 差异 lncRNA)
top50_lncRNA <- res_filtered %>% slice_head(n = 50) %>% pull(gene_id)
top50_counts <- assay(rlog(dds))[top50_lncRNA, ] # rlog 标准化,降低异方差影响
pheatmap(top50_counts,
annotation_col = group_info,
show_rownames = FALSE,
scale = "row", # 行标准化(便于比较基因表达模式)
color = colorRampPalette(c("blue", "white", "red"))(100),
main = "Top 50 差异 lncRNA 表达热图")
ggsave("./plots/lncRNA_heatmap.png", width = 10, height = 8, dpi = 300)
3. miRNA 差异分析(limma 示例)
miRNA 表达数据常为 TPM 格式,适合用 limma 进行差异分析
R
# 1. 读取 miRNA 表达矩阵(TPM 格式)
miRNA_tpm <- read.delim("./quantification/miRNA_tpm.txt", row.names = 1)
miRNA_tpm <- miRNA_tpm[, rownames(group_info)] # 匹配样本顺序
# 2. 数据转换(TPM 取对数,使分布更接近正态)
miRNA_log <- log2(miRNA_tpm + 1) # +1 避免 log(0)
# 3. 构建 limma 设计矩阵
design <- model.matrix(~ 0 + group, data = group_info)
colnames(design) <- gsub("group", "", colnames(design))
contrast.matrix <- makeContrasts(case - control, levels = design)
# 4. 差异分析
fit <- lmFit(miRNA_log, design)
fit2 <- contrasts.fit(fit, contrast.matrix)
fit2 <- eBayes(fit2) # 经验贝叶斯调整
res_miRNA <- topTable(fit2, coef = 1, number = Inf, adjust = "fdr")
# 5. 筛选差异 miRNA(padj < 0.05 且 |log2FC| > 1)
res_miRNA_filtered <- res_miRNA %>%
rownames_to_column("miRNA_id") %>%
filter(adj.P.Val < 0.05 & abs(logFC) > 1)
# 保存结果
write.csv(res_miRNA_filtered, "./differential/miRNA_diff_expr.csv", row.names = FALSE)
关键说明:
- 差异筛选阈值可根据研究需求调整(如严格筛选用 padj <0.01、|log2FC|> 2)。
- 若样本量小(n < 3),建议用 edgeR 替代 DESeq2,抗噪声能力更强。
五、第四步:ceRNA 网络构建
ceRNA 网络构建的核心是 "筛选差异分子间的 miRNA 介导的调控关系",需经历 "靶标预测→相互作用筛选→网络构建" 三个步骤。
1. 靶标预测(miRNA 与 ceRNA/mRNA 结合位点预测)
使用 TargetScan(动物 miRNA 靶标预测工具)结合 Python 脚本批量预测。
python
import pandas as pd
from targetscan import TargetScan # 需提前安装:pip install targetscan
# 1. 读取差异分子列表
diff_lncRNA <- pd.read_csv("./differential/lncRNA_diff_expr.csv")["gene_id"].tolist()
diff_circRNA <- pd.read_csv("./differential/circRNA_diff_expr.csv")["circRNA_ID"].tolist()
diff_mRNA <- pd.read_csv("./differential/mRNA_diff_expr.csv")["gene_id"].tolist()
diff_miRNA <- pd.read_csv("./differential/miRNA_diff_expr.csv")["miRNA_id"].tolist()
# 2. 批量预测 miRNA 与 mRNA 的结合位点(TargetScan)
ts = TargetScan()
mirna_mrna_pairs = []
for mirna in diff_miRNA:
# 预测该 miRNA 的所有靶标 mRNA
targets = ts.predict(mirna)
# 筛选出差异 mRNA 中的靶标
target_mrna = targets[targets["gene_id"].isin(diff_mRNA)]
if not target_mrna.empty:
target_mrna["miRNA_id"] = mirna
mirna_mrna_pairs.append(target_mrna[["miRNA_id", "gene_id", "context_score"]])
# 合并结果(context_score 越小,结合亲和力越强)
mirna_mrna_df = pd.concat(mirna_mrna_pairs, ignore_index = True)
mirna_mrna_df = mirna_mrna_df[mirna_mrna_df["context_score"] < -0.3] # 筛选高亲和力结合对
# 3. 预测 miRNA 与 lncRNA/circRNA 的结合位点(RNAhybrid)
# RNAhybrid 命令行调用示例(需提前安装 RNAhybrid)
def predict_mirna_ceRNA(mirna, ceRNA_list, ceRNA_type="lncRNA"):
ceRNA_mirna_pairs = []
for ceRNA in ceRNA_list:
# 假设已获取 ceRNA 的序列(需从参考基因组中提取,此处省略序列提取步骤)
ceRNA_seq = get_ceRNA_sequence(ceRNA) # 自定义函数:根据 ID 提取序列
# 调用 RNAhybrid 预测结合自由能(ΔG < -20 kcal/mol 为高亲和力)
result = os.popen(f"echo -e '{mirna_seq}\\n{ceRNA_seq}' | RNAhybrid -s 2 -m 80 -v 3").read()
# 解析结果,提取结合自由能
delta_g = parse_rnahybrid_result(result) # 自定义函数:解析 RNAhybrid 输出
if delta_g < -20:
ceRNA_mirna_pairs.append({"miRNA_id": mirna, "ceRNA_id": ceRNA, "delta_g": delta_g, "ceRNA_type": ceRNA_type})
return ceRNA_mirna_pairs
# 4. 合并所有相互作用对(miRNA-ceRNA + miRNA-mRNA)
ceRNA_mirna_df = pd.DataFrame(predict_mirna_ceRNA(diff_miRNA, diff_lncRNA, "lncRNA"))
circRNA_mirna_df = pd.DataFrame(predict_mirna_ceRNA(diff_miRNA, diff_circRNA, "circRNA"))
all_interactions = pd.concat([ceRNA_mirna_df, circRNA_mirna_df, mirna_mrna_df], ignore_index = True)
# 保存相互作用列表
all_interactions.to_csv("./ceRNA/miRNA_interactions.csv", index = False)
2. ceRNA 网络构建与可视化
基于相互作用对,用 igraph 构建网络,Cytoscape 可视化核心节点。
R
library(igraph)
library(tidyverse)
# 1. 读取相互作用数据
interactions <- read.csv("./ceRNA/miRNA_interactions.csv")
# 2. 构建网络节点数据框(包含节点 ID 和类型)
nodes_lncRNA <- data.frame(
id = unique(interactions$ceRNA_id[interactions$ceRNA_type == "lncRNA"]),
type = "lncRNA"
)
nodes_circRNA <- data.frame(
id = unique(interactions$ceRNA_id[interactions$ceRNA_type == "circRNA"]),
type = "circRNA"
)
nodes_miRNA <- data.frame(
id = unique(interactions$miRNA_id),
type = "miRNA"
)
nodes_mRNA <- data.frame(
id = unique(interactions$gene_id),
type = "mRNA"
)
all_nodes <- rbind(nodes_lncRNA, nodes_circRNA, nodes_miRNA, nodes_mRNA)
# 3. 构建网络边数据框(相互作用关系)
edges <- interactions %>%
mutate(
from = ifelse(!is.na(ceRNA_id), ceRNA_id, miRNA_id),
to = ifelse(!is.na(gene_id), gene_id, miRNA_id)
) %>%
select(from, to, type = ceRNA_type)
# 4. 用 igraph 构建网络
g <- graph_from_data_frame(d = edges, vertices = all_nodes, directed = FALSE)
# 5. 网络拓扑分析(筛选核心节点)
# 计算节点度(连接的节点数,度越高越核心)
node_degree <- degree(g)
core_nodes <- names(node_degree)[node_degree >= 5] # 筛选度≥5 的核心节点
# 6. 提取核心网络(仅包含核心节点及相互作用)
core_g <- induced_subgraph(g, vids = core_nodes)
# 7. 保存网络为 Cytoscape 兼容格式(CSV)
write.csv(as_data_frame(core_g, what = "vertices"), "./ceRNA/core_nodes.csv", row.names = FALSE)
write.csv(as_data_frame(core_g, what = "edges"), "./ceRNA/core_edges.csv", row.names = FALSE)
# 8. R 可视化核心网络
V(core_g)$color <- case_when(
V(core_g)$type == "lncRNA" ~ "red",
V(core_g)$type == "circRNA" ~ "blue",
V(core_g)$type == "miRNA" ~ "green",
V(core_g)$type == "mRNA" ~ "orange"
)
plot(core_g,
vertex.size = 5,
vertex.label.cex = 0.6,
edge.width = 1,
layout = layout_with_fr, # 力导向布局
main = "ceRNA 核心调控网络")
Cytoscape 可视化步骤:
- 打开 Cytoscape,导入
core_nodes.csv和core_edges.csv。 - 在 "Style" 面板设置节点颜色(按类型区分)、大小(按度排序)。
- 用 "Layout"→"Force-directed" 优化网络布局,导出高分辨率图片。
六、第五步:功能富集分析
功能富集分析用于解释 ceRNA 网络的生物学意义,核心是分析差异 mRNA 或网络中的 mRNA 富集的 GO 术语(生物过程、细胞组分、分子功能)和 KEGG 通路。
1. GO/KEGG 富集分析(clusterProfiler 示例)
R
library(clusterProfiler)
library(org.Hs.eg.db) # 人类基因注释库(小鼠用 org.Mm.eg.db)
library(ggplot2)
# 1. 读取差异 mRNA 列表(需转换为 Entrez ID 或 Symbol)
diff_mrna <- read.csv("./differential/mRNA_diff_expr.csv")["gene_id"] # 假设 gene_id 为 Ensembl ID
# 2. 转换 Ensembl ID 为 Entrez ID(富集分析需 Entrez ID)
mrna_entrez <- bitr(
diff_mrna$gene_id,
fromType = "ENSEMBL",
toType = "ENTREZID",
OrgDb = org.Hs.eg.db
)
# 3. GO 富集分析
go_enrich <- enrichGO(
gene = mrna_entrez$ENTREZID,
OrgDb = org.Hs.eg.db,
keyType = "ENTREZID",
ont = "BP", # BP:生物过程(可选 MF/CC)
pAdjustMethod = "fdr",
qvalueCutoff = 0.05
)
# 可视化:GO 富集气泡图
dotplot(go_enrich, showCategory = 15, title = "差异 mRNA GO 富集分析(BP)") +
theme(axis.text.y = element_text(size = 10))
ggsave("./enrichment/GO_BP_dotplot.png", width = 12, height = 8, dpi = 300)
# 4. KEGG 富集分析
kegg_enrich <- enrichKEGG(
gene = mrna_entrez$ENTREZID,
organism = "hsa", # 人类:hsa,小鼠:mmu
pvalueCutoff = 0.05,
qvalueCutoff = 0.1
)
# 可视化:KEGG 富集气泡图
dotplot(kegg_enrich, showCategory = 15, title = "差异 mRNA KEGG 富集分析") +
theme(axis.text.y = element_text(size = 10))
ggsave("./enrichment/KEGG_dotplot.png", width = 12, height = 8, dpi = 300)
# 5. 保存富集结果
write.csv(as.data.frame(go_enrich), "./enrichment/GO_enrichment.csv", row.names = FALSE)
write.csv(as.data.frame(kegg_enrich), "./enrichment/KEGG_enrichment.csv", row.names = FALSE)
2. GSEA 分析(基因集富集分析)
适用于探索差异表达不显著但功能相关的基因集,补充 GO/KEGG 分析的局限性。
R
# 1. 准备 GSEA 输入数据(基因表达量排序文件)
# 读取 mRNA 表达矩阵(TPM 格式)
mrna_tpm <- read.delim("./quantification/mRNA_tpm.txt", row.names = 1)
# 计算病例组 vs 对照组的平均表达量比值(log2FC)
case_samples <- rownames(group_info)[group_info$group == "case"]
control_samples <- rownames(group_info)[group_info$group == "control"]
mrna_log2fc <- log2(rowMeans(mrna_tpm[, case_samples]) / rowMeans(mrna_tpm[, control_samples]) + 1)
# 构建排序文件(基因名 + log2FC)
gsea_rnk <- data.frame(
gene = names(mrna_log2fc),
log2fc = mrna_log2fc
) %>%
arrange(desc(log2fc)) %>%
select(gene, log2fc)
# 保存排序文件
write.table(gsea_rnk, "./enrichment/GSEA_rnk.rnk", sep = "\t", quote = FALSE, row.names = FALSE)
# 2. 运行 GSEA(需下载 GSEA 软件,手动运行或调用 R 接口)
# 此处为 GSEA 软件操作步骤:
# 1. 打开 GSEA,导入 rnk 文件和表型文件(分组信息)
# 2. 选择基因集(如 c2.cp.kegg.v7.5.1.symbols.gmt)
# 3. 运行 GSEA,查看富集结果(FDR < 0.25 为显著富集)
# 3. 可视化 GSEA 结果(核心通路富集图)
gsea_result <- read.delim("./enrichment/GSEA_results.txt") # GSEA 输出结果
gseaplot2(go_enrich, geneSetID = 1, title = gsea_result$Description[1]) # 绘制 top1 通路
ggsave("./enrichment/GSEA_plot.png", width = 10, height = 6, dpi = 300)
七、第六步:实验功能验证
生信分析结果需通过湿实验验证,核心验证方向包括 "分子表达验证→调控关系验证→功能表型验证",以下为关键实验设计与步骤。
1. 分子表达验证(qPCR)
验证生信筛选的差异 lncRNA/circRNA/mRNA/miRNA 在临床样本或细胞系中的表达趋势。
- 实验材料:临床样本(病例组 vs 对照组,n ≥ 30)、细胞系(如 A549 肺癌细胞)。
- 关键步骤 :
- 提取总 RNA(Trizol 法),检测 RNA 纯度(A260/A280 = 1.8-2.0)。
- 反转录:lncRNA/mRNA 用 oligo (dT) 引物,circRNA/miRNA 用特异性引物。
- qPCR 扩增:用 SYBR Green 试剂盒,设置内参基因(GAPDH 用于 mRNA/lncRNA,U6 用于 miRNA)。
- 结果分析:用 2^(-ΔΔCt) 法计算相对表达量,t 检验验证组间差异。
- 验证标准:qPCR 结果与生信分析的表达趋势一致(如生信显示高表达,qPCR 也需验证高表达)。
2. 调控关系验证(双荧光素酶报告基因实验)
验证 ceRNA 与 miRNA、miRNA 与 mRNA 的直接结合关系。
- 实验设计 :
- 构建野生型(WT)报告载体:将 ceRNA/mRNA 中 miRNA 结合位点的序列克隆到 pmirGLO 载体的 3' UTR 区。
- 构建突变型(MUT)报告载体:突变结合位点的核心碱基(如种子区)。
- 共转染:将 WT/MUT 载体与 miRNA mimics/NC(阴性对照)共转染 293T 细胞。
- 结果判断:若 miRNA mimics 转染后,WT 载体的荧光素酶活性显著降低(≥30%),而 MUT 载体无显著变化,证明直接结合。
3. 功能表型验证(细胞实验)
验证核心 ceRNA(lncRNA/circRNA)对细胞增殖、迁移、侵袭等表型的影响。
- 实验步骤 :
- 细胞转染:用 siRNA 沉默 lncRNA/circRNA,或用过表达载体上调其表达。
- 功能实验:
- 增殖能力:CCK-8 assay、EdU 染色。
- 迁移 / 侵袭能力:Transwell assay、划痕愈合实验。
- 凋亡能力:流式细胞术(Annexin V/PI 染色)。
- 验证逻辑:若沉默核心 ceRNA 后,细胞增殖 / 迁移能力显著降低,且其靶标 miRNA 表达升高、下游 mRNA 表达降低,则验证 ceRNA 网络的调控功能。
八、常见问题与解决方案
- 数据比对率低:检查参考基因组版本是否匹配(如人类用 hg38 而非 hg19),或测序数据存在批次效应,需用 sva 包校正。
- 差异分子过少:降低筛选阈值(如 padj <0.1、|log2FC|> 0.8),或增加样本量,避免假阴性。
- ceRNA 网络假阳性高:仅保留 "高亲和力结合对"(如 RNAhybrid ΔG < -25 kcal/mol),结合共表达分析(ceRNA 与 mRNA 表达正相关)。
- 富集结果无显著通路:扩大差异 mRNA 筛选范围,或使用 GSEA 分析替代 GO/KEGG,探索潜在功能关联。
九、总结
非编码 RNA 分析是一个 "从数据到功能" 的系统工程,核心流程可概括为:数据下载与质控→预处理定量→差异筛选→网络构建→功能富集→实验验证。生信分析阶段需注重数据质量控制和工具选择,避免因参数不当导致结果偏差;实验验证阶段需聚焦核心分子和调控关系,确保生信预测的可靠性。
本文提供的代码模板可直接适配人类 / 小鼠的 RNA-seq 数据,研究者可根据自身研究对象(如肿瘤、代谢疾病)调整筛选阈值和实验方案。记住:ncRNA 研究的核心是 "功能机制",生信分析是发现候选分子的工具,最终需通过实验验证揭示其在生物过程中的作用。