完整的单细胞分析流程——特征(基因)选择
背景
我们经常在探索性分析中使用scRNA-seq数据来表征细胞间的异质性。诸如聚类和降维之类的过程会根据细胞的基因表达谱对细胞进行比较,这涉及将每个基因的差异汇总为一对细胞之间的单个(不相似)或相似的度量。用于此计算的基因的选择对度量的行为和下游分析方法的性能有重大影响。我们希望选择包含与系统生物学相关且有用信息的基因,同时删除包含随机噪声的基因。这旨在保留有趣的生物学过程的结构而不会使该结构模糊不清,并减小数据大小以提高后续步骤的计算效率。
特征选择的最简单方法是根据基因在整个细胞群之间的表达量来选择变化最大的基因。假定与仅受技术噪声或基线水平的“无用”生物学变异(例如,来自转录爆发)影响的其他基因相比,真正的生物学差异将表现为受影响基因的变异增加。有几种方法可用于量化每个基因的变异并选择适当的一组高度可变的基因(HVG)。我们将在下面使用10X PBMC数据集进行讨论,以进行演示:
#--- loading ---#
library(DropletTestFiles)
raw.path <- getTestFile("tenx-2.1.0-pbmc4k/1.0.0/raw.tar.gz")
out.path <- file.path(tempdir(), "pbmc4k")
untar(raw.path, exdir=out.path)
library(DropletUtils)
fname <- file.path(out.path, "raw_gene_bc_matrices/GRCh38")
sce.pbmc <- read10xCounts(fname, col.names=TRUE)
#--- gene-annotation ---#
library(scater)
rownames(sce.pbmc) <- uniquifyFeatureNames(
rowData(sce.pbmc)$ID, rowData(sce.pbmc)$Symbol)
library(EnsDb.Hsapiens.v86)
location <- mapIds(EnsDb.Hsapiens.v86, keys=rowData(sce.pbmc)$ID,
column="SEQNAME", keytype="GENEID")
#--- cell-detection ---#
set.seed(100)
e.out <- emptyDrops(counts(sce.pbmc))
sce.pbmc <- sce.pbmc[,which(e.out$FDR <= 0.001)]
#--- quality-control ---#
stats <- perCellQCMetrics(sce.pbmc, subsets=list(Mito=which(location=="MT")))
high.mito <- isOutlier(stats$subsets_Mito_percent, type="higher")
sce.pbmc <- sce.pbmc[,!high.mito]
#--- normalization ---#
library(scran)
set.seed(1000)
clusters <- quickCluster(sce.pbmc)
sce.pbmc <- computeSumFactors(sce.pbmc, cluster=clusters)
sce.pbmc <- logNormCounts(sce.pbmc)
sce.pbmc
## class: SingleCellExperiment
## dim: 33694 3985
## metadata(1): Samples
## assays(2): counts logcounts
## rownames(33694): RP11-34P13.3 FAM138A ... AC213203.1 FAM231B
## rowData names(2): ID Symbol
## colnames(3985): AAACCTGAGAAGGCCT-1 AAACCTGAGACAGACC-1 ...
## TTTGTCAGTTAAGACA-1 TTTGTCATCCCAAGAT-1
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## altExpNames(0):
还有416B数据集:
#--- loading ---#
library(scRNAseq)
sce.416b <- LunSpikeInData(which="416b")
sce.416b$block <- factor(sce.416b$block)
#--- gene-annotation ---#
library(AnnotationHub)
ens.mm.v97 <- AnnotationHub()[["AH73905"]]
rowData(sce.416b)$ENSEMBL <- rownames(sce.416b)
rowData(sce.416b)$SYMBOL <- mapIds(ens.mm.v97, keys=rownames(sce.416b),
keytype="GENEID", column="SYMBOL")
rowData(sce.416b)$SEQNAME <- mapIds(ens.mm.v97, keys=rownames(sce.416b),
keytype="GENEID", column="SEQNAME")
library(scater)
rownames(sce.416b) <- uniquifyFeatureNames(rowData(sce.416b)$ENSEMBL,
rowData(sce.416b)$SYMBOL)
#--- quality-control ---#
mito <- which(rowData(sce.416b)$SEQNAME=="MT")
stats <- perCellQCMetrics(sce.416b, subsets=list(Mt=mito))
qc <- quickPerCellQC(stats, percent_subsets=c("subsets_Mt_percent",
"altexps_ERCC_percent"), batch=sce.416b$block)
sce.416b <- sce.416b[,!qc$discard]
#--- normalization ---#
library(scran)
sce.416b <- computeSumFactors(sce.416b)
sce.416b <- logNormCounts(sce.416b)
sce.416b
## class: SingleCellExperiment
## dim: 46604 185
## metadata(0):
## assays(2): counts logcounts
## rownames(46604): 4933401J01Rik Gm26206 ... CAAA01147332.1
## CBFB-MYH11-mcherry
## rowData names(4): Length ENSEMBL SYMBOL SEQNAME
## colnames(185): SLX-9555.N701_S502.C89V9ANXX.s_1.r_1
## SLX-9555.N701_S503.C89V9ANXX.s_1.r_1 ...
## SLX-11312.N712_S507.H5H5YBBXX.s_8.r_1
## SLX-11312.N712_S517.H5H5YBBXX.s_8.r_1
## colData names(10): Source Name cell line ... block sizeFactor
## reducedDimNames(0):
## altExpNames(2): ERCC SIRV
量化基因的变化程度
log转化数据的变化程度
量化每个基因变异的最简单方法是简单地计算细胞群间所有细胞的每个基因的对数归一化后的表达值(为简单起见,称为“对数值”)的方差。这具有一个优点,即特征基因的选择基于用于后续下游步骤的相同对数值。特别是,对数值的方差最大的基因将对细胞之间的欧几里得距离贡献最大。通过在此处使用对数值,我们可以确保在整个分析过程中对异质性的定量定义是一致的。
每个基因的方差的计算很简单,但是特征选择需要对均方差关系进行建模。正如在数据均一化中简要讨论的那样,对数转换无法实现完美的方差稳定化,这意味着基因的方差更多地是由其丰度驱动的,而不是其潜在的生物异质性。为了说明这种影响,我们使用modelGeneVar()
函数描绘所有基因的丰度差异的趋势(图1)。
library(scran)
dec.pbmc <- modelGeneVar(sce.pbmc)
# Visualizing the fit:
fit.pbmc <- metadata(dec.pbmc)
plot(fit.pbmc$mean, fit.pbmc$var, xlab="Mean of log-expression",
ylab="Variance of log-expression")
curve(fit.pbmc$trend(x), col="dodgerblue", add=TRUE, lwd=2)
PBMC数据集中的差异是平均值的函数。 每个点代表一个基因,而蓝线代表适合所有基因变化度的趋势。
在任何给定的丰度下,我们都假定大多数基因的表达谱受随机技术噪声的影响。 在此假设下,我们的趋势代表了技术噪声作为丰度函数的估计。 然后,我们将每个基因的总方差分解为技术成分,即该基因丰度时趋势的拟合值; 生物成分,定义为总差异与技术成分之间的差。 此生物学成分代表每个基因的“有趣”变异,可用作HVG选择的指标。
# Ordering by most interesting genes for inspection.
dec.pbmc[order(dec.pbmc$bio, decreasing=TRUE),]
## DataFrame with 33694 rows and 6 columns
## mean total tech bio p.value FDR
## <numeric> <numeric> <numeric> <numeric> <numeric> <numeric>
## LYZ 1.95605 5.05854 0.835343 4.22320 1.10534e-270 2.17409e-266
## S100A9 1.93416 4.53551 0.835439 3.70007 2.71036e-208 7.61572e-205
## S100A8 1.69961 4.41084 0.824342 3.58650 4.31570e-201 9.43173e-198
## HLA-DRA 2.09785 3.75174 0.831239 2.92050 5.93940e-132 4.86758e-129
## CD74 2.90176 3.36879 0.793188 2.57560 4.83929e-113 2.50484e-110
## ... ... ... ... ... ... ...
## TMSB4X 6.08142 0.441718 0.679215 -0.237497 0.992447 1
## PTMA 3.82978 0.486454 0.731275 -0.244821 0.990002 1
## HLA-B 4.50032 0.486130 0.739577 -0.253447 0.991376 1
## EIF1 3.23488 0.482869 0.768946 -0.286078 0.995135 1
## B2M 5.95196 0.314948 0.654228 -0.339280