背景知识
gene_lengths(基因长度)是计算基因表达量时的一个关键参数,主要用于消除因基因本身长短不同而对定量结果造成的影响,让不同基因的表达水平更具可比性。
下面的表格能帮你快速理解它的核心定义和常见计算方法:
核心定义 为什么需要它? 最常见的计算方法
指一个基因的有效转录区域的总长度,通常以碱基对为单位。 在RNA-seq中,更长的基因在随机打断和测序过程中,会有更多片段来自该基因,导致其原始读数更高。直接比较不同基因的counts会误以为长基因表达量更高。 非冗余外显子长度之和:将一个基因的所有外显子(exon)合并,去除重叠部分后计算总长度。
💡 基因长度的不同计算方式
在实际分析中,根据研究目的的不同,"基因长度"有几种常见的定义和计算方法:
- 非冗余外显子长度之和:这是最常用和推荐的方法。它计算的是一个基因所有外显子(即编码区和非编码区)合并后的总长度,能最准确地代表该基因转录本的潜在长度。
- 非冗余CDS长度之和:只计算编码蛋白的外显子(CDS区)的总长度。如果你特别关注蛋白质的编码潜力,这种方法可能更合适。
- 最长转录本长度:对于有多个可变转录本的基因,选择其最长的那个转录本的长度作为该基因的代表长度。
- 多个转录本长度的平均值:计算一个基因所有转录本长度的平均值,作为一种折中的方案。
🧬 如何获取基因长度
通常,我们需要从基因注释文件中提取基因长度信息。使用R语言的 GenomicFeatures 包可以方便地完成这项工作。基本步骤如下:
加载必要的包
library(GenomicFeatures)
从GTF或GFF文件创建转录组数据库
txdb <- makeTxDbFromGFF(“your_annotation_file.gtf”, format=“gtf”)
按基因提取所有外显子,并计算每个基因的非冗余外显子总长度
exons_per_gene <- exonsBy(txdb, by = “gene”)
gene_lengths <- sum(width(reduce(exons_per_gene)))
转换为数据框,方便使用
gene_lengths_df <- data.frame(
gene_id = names(gene_lengths),
length = as.numeric(gene_lengths)
)
💻 在表达量标准化中的应用
基因长度最主要的应用场景就是将原始读数转换为TPM或FPKM/RPKM这类标准化表达量。以你之前遇到的TPM计算代码为例:
计算RPK (Reads Per Kilobase):先对基因长度进行校正
rpk <- count_mat / (gene_lengths / 1000)
计算TPM:再对测序深度进行校正
tpm <- t( t(rpk) / colSums(rpk) ) * 1e6
• 第一步:rpk <- count_mat / (gene_lengths / 1000)。这一步的目的是消除基因长度的影响。将每个基因的原始读数除以其长度(以千碱基为单位),得到"每千碱基的读数"。这样,长基因和短基因就站在了同一起跑线上。
• 第二步:tpm <- t( t(rpk) / colSums(rpk) ) * 1e6。这一步的目的是消除样本间总测序深度(即总读数)的差异。将每个基因的RPK除以该样本所有基因RPK的总和,再乘以100万,得到"每百万转录本数"。这使得每个样本的TPM总和都是100万,便于跨样本比较。
⚠️ 注意事项
• 确保顺序一致:在计算时,务必确保gene_lengths向量中的基因顺序与表达量矩阵中的行名完全一致。
• 使用有效长度:更精确的计算会使用"有效长度",它会考虑测序片段的长度分布,但通常情况下用上述总外显子长度已足够。
• 注释文件版本:不同来源或版本的注释文件(如UCSC, Ensembl, GENCODE)计算的基因长度可能会有细微差异。
希望这些解释能帮助你更好地理解gene_lengths这个概念及其在数据分析中的重要性!
sample_counts <- rowSums(count_mat) # 总 counts
gene_lengths # 如果你有序列长度向量
tpm <- t( t(count_mat) / gene_lengths ) # 每长度
tpm <- tpm / colSums(tpm) * 1e6 # 百万标准化
sample_tpm <- rowMeans(tpm)
计算基因表达量TPM(Transcripts Per Million)值的经典步骤
。下面我为你详细解释每一步的意图、背后的原理,并提供一些注意事项。
📌 TPM计算原理与步骤分解
首先,TPM的计算目标是对基因的表达量进行标准化,使其既考虑不同样本之间的测序深度差异,也考虑基因本身长度差异,从而使得不同基因在不同样本间的表达量具有可比性。
下面的表格清晰地展示了整个计算流程和每一步的核心目的:
步骤 代码 目的解释 数学含义
-
计算总Counts sample_counts <- rowSums(count_mat) 计算每个基因在所有样本中的原始读数(Counts)之和。这通常用于观察基因的整体表达水平,但并非TPM计算的必需步骤。 对每行(每个基因)求和
-
长度校正 tpm <- t( t(count_mat) / gene_lengths ) 核心步骤1:消除基因长度对表达量的影响。将每个基因的Counts除以其有效长度(例如,非冗余外显子长度之和),得到“每碱基的读数”。 Counts(i,s) / Length(i)
-
样本标准化 tpm <- tpm / colSums(tpm) * 1e6 核心步骤2:消除样本间测序深度差异。将每个样本经过长度校正后的值,除以该样本所有基因校正值之和,再乘以100万。使得每个样本的TPM总和为100万。 [Counts(i,s)/Length(i)] / [Σ(Counts(j,s)/Length(j))] * 10^6
-
计算平均表达 sample_tpm <- rowMeans(tpm) 后续分析:计算每个基因在多个样本中的平均TPM值,用于比较基因间的相对表达水平。 对每行(每个基因)求均值
💡 关键细节与注意事项
在实际操作中,以下几个细节对结果的准确性至关重要:
-
基因长度向量 gene_lengths:这是计算中的关键输入。它的长度必须与 count_mat 矩阵的行数(基因数量)完全一致,并且顺序要一一对应。你需要一个包含每个基因有效长度的向量,其获取方式可以是:
◦ 使用 Bioconductor 的注释包(如 TxDb.Hsapiens.UCSC.hg19.knownGene),通过计算非冗余外显子长度之和或最长转录本长度来获得。◦ 使用 biomaRt 包 从 Ensembl 数据库在线查询获取。
-
矩阵转置操作 t( ):步骤2中的双重转置 t( t(count_mat) / gene_lengths ) 是一个巧妙的技巧。因为R语言中矩阵除以向量的操作是按列进行的。我们的目标是对每一行(每个基因)的Counts除以其对应的长度,所以需要先转置矩阵,让“基因”变成列,进行按列除法后,再转置回来恢复原始维度。
-
TPM与FPKM/RPKM的区别:TPM和FPKM都是经过长度和测序深度校正的单位,但它们的标准化思路有细微, 但至关重要的差别:
◦ FPKM 是先对长度做校正,然后对测序深度做校正。◦ TPM 是先对长度做校正,然后对校正后的总值进行标准化。
◦ 结果就是,一个样本中所有基因的TPM值总和始终为100万,这使得TPM在不同样本间的比较更为直观和稳定。因此,TPM现在被更广泛地推荐使用。
🛠️ 主要应用场景
TPM值标准化后,主要用于:
• 比较同一样本内不同基因的表达水平:例如,找出哪个基因在某个细胞或组织里表达最高。
• 比较不同样本间同一基因的表达水平:例如,观察某个基因在疾病组和对照组中的表达差异。
希望这份详细的解释能帮助你透彻理解TPM的计算过程!如果你对获取基因长度或代码实现还有其他疑问,可以随时再问我。
t(t(rpk) / colSums(rpk)) * 1e6 这一行“两次转置”的目的只有一句话:
让 R 把“每个基因在该细胞里的占比”按 列 方向做向量除法,而 R 的
/默认是 列-wise 操作。
1. 先看清维度
假设
rpk:基因 × 细胞 矩阵,维度 G × C
cell1 cell2 cell3
geneA 10 20 30
geneB 40 50 60
geneC 70 80 90
2. 我们想干什么?
TPM 第 2 步:
把每个细胞内部所有基因的 RPK 加总 → 得到该细胞的 library size(以 RPK 为单位),然后把该细胞里每个基因的 RPK 除以这个总和,再乘 1e6。
也就是
TPM_gc = RPK_gc / (sum_g RPK_g,c) * 1e6
按列做除法。
3. R 的 / 规则
- 如果
x是矩阵,y是向量,那么
x / y会把 y 的每个元素对应到 x 的每一列 去做除法(column-wise)。
维度必须length(y) == ncol(x)。
但我们现在的矩阵是 G × C,而 colSums(rpk) 长度 = C。
直接写 rpk / colSums(rpk) 会把“每列”除以对应的 colSums,正好是我们想要的列方向除法!
4. 那为什么还要两次转置?
历史原因 / 防呆写法 / 早期代码 copy-paste 习惯。
-
早期有人担心“如果矩阵是 细胞 × 基因 呢?”
先t(rpk)变成 C × G,此时colSums()长度 = G,再/就是按基因方向除,不符合 TPM 定义。
于是再t()回来,确保最终维度还是 G × C。 -
另一种场景:
如果你手里拿到的是 细胞 × 基因 矩阵,那么t(t(rpk) / colSums(rpk))就是“先转置成基因×细胞,按列除,再转置回细胞×基因”——通用模板,不管原始维度怎样,写完一定对。
5. 现代写法(更直观)
只要你能 100% 确定 rpk 是 基因 × 细胞,可以直接:
tpm <- rpk / colSums(rpk) * 1e6
一次转置都不需要,结果完全一样。
一句话总结
- 两次转置 = 通用模板,不管矩阵是“基因×细胞”还是“细胞×基因”都能按 列 完成 TPM 归一化。
- 如果你已明确维度是 基因×细胞,
t(t(...))完全可以省掉,直接rpk / colSums(rpk) * 1e6即可。
1483

被折叠的 条评论
为什么被折叠?



