使用scran分析单细胞数据

官网教程:Scran1.20.1(最新)。本教程使用的是Scran1.18.7,有几个函数不太一样。

# 查看安装的scran的网页版教程:
browseVignettes("scran")
1. 介绍

The scran package implements methods to perform low-level processing of scRNA-seq data, including cell cycle phase assignment, variance modelling and testing for marker genes and gene-gene correlations. This vignette provides brief descriptions of these methods and some toy examples to demonstrate their use.
更多教程

2. 数据准备

这个数据集是CEL-seq测的人类胰腺数据集,由SingleCellExperiment包提供。

library(scRNAseq)
sce <- GrunPancreasData()
sce
## class: SingleCellExperiment 
## dim: 20064 1728 
## metadata(0):
## assays(1): counts
## rownames(20064): A1BG-AS1__chr19 A1BG__chr19 ... ZZEF1__chr17
##   ZZZ3__chr1
## rowData names(2): symbol chr
## colnames(1728): D2ex_1 D2ex_2 ... D17TGFB_95 D17TGFB_96
## colData names(2): donor sample
## reducedDimNames(0):
## mainExpName: endogenous
## altExpNames(1): ERCC
View(sce)

关于sce对象,参考: https://www.jianshu.com/p/533aa6c50a38

首先进行一些(粗略的)质控以去除counts过低或spike-in过高的细胞。

library(scuttle)
qcstats <- perCellQCMetrics(sce) 
qcfilter <- quickPerCellQC(qcstats, percent_subsets="altexps_ERCC_percent")
sce <- sce[,!qcfilter$discard]
summary(qcfilter$discard)
##    Mode   FALSE    TRUE 
## logical    1291     437
3. 标准化(Normalizing cell-specific biases)

scran中的标准化使用computeSumFactors()函数,该过程是基于反卷积方法:先合并许多细胞的计数以避免drop-out问题,然后将基于池的量化因子(scale factor)“去卷积”为cell-based factors,以进行特定细胞的标准化。而标准化之前对细胞进行聚类(quickCluster)不是必需的,不过减少cluster中细胞之间的差异表达基因数量确实可以提高标准化的准确性。

library(scran)
clusters <- quickCluster(sce)
sce <- computeSumFactors(sce, clusters=clusters)
summary(sizeFactors(sce))
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 0.006722 0.442629 0.801312 1.000000 1.295809 9.227575

也可以使用spike-in来进行标准化

sce2 <- computeSpikeFactors(sce, "ERCC")
summary(sizeFactors(sce2))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.01041 0.57760 0.88667 1.00000 1.27679 7.43466

不管使用哪种方法来计算量化因子,计算标准化的表达值都是使用scuttle包的logNormCounts()函数。标准化后的表达矩阵可以用于下游的聚类和降维等分析。

sce <- logNormCounts(sce)
4. 差异建模(Variance modelling)
dec <- modelGeneVar(sce)
plot(dec$mean, dec$total, xlab="Mean log-expression", ylab="Variance")
curve(metadata(dec)$trend(x), col="blue", add=TRUE)
dec2 <- modelGeneVarWithSpikes(sce, 'ERCC')
plot(dec2$mean, dec2$total, xlab="Mean log-expression", ylab="Variance")
points(metadata(dec2)$mean, metadata(dec2)$var, col="red")
curve(metadata(dec2)$trend(x), col="blue", add=TRUE)
# Turned off weighting to avoid overfitting for each donor.
dec3 <- modelGeneVar(sce, block=sce$donor, density.weights=FALSE)
per.block <- dec3$per.block
par(mfrow=c(3, 2))
for (i in seq_along(per.block)) {
    decX <- per.block[[i]]
    plot(decX$mean, decX$total, xlab="Mean log-expression", 
        ylab="Variance", main=names(per.block)[i])
    curve(metadata(decX)$trend(x), col="blue", add=TRUE)
}
# Get the top 10% of genes.
top.hvgs <- getTopHVGs(dec, prop=0.1)

# Get the top 2000 genes.
top.hvgs2 <- getTopHVGs(dec, n=2000)

# Get all genes with positive biological components.
top.hvgs3 <- getTopHVGs(dec, var.threshold=0)

# Get all genes with FDR below 5%.
top.hvgs4 <- getTopHVGs(dec, fdr.threshold=0.05)
# Running the PCA with the 10% of HVGs.
library(scater)
sce <- runPCA(sce, subset_row=top.hvgs)
reducedDimNames(sce)
5. 自动化PC选择
sced <- denoisePCA(sce, dec2, subset.row=getTopHVGs(dec2, prop=0.1))
ncol(reducedDim(sced, "PCA"))
## [1] 50
output <- getClusteredPCs(reducedDim(sce))
npcs <- metadata(output)$chosen
reducedDim(sce, "PCAsub") <- reducedDim(sce, "PCA")[,1:npcs,drop=FALSE]
npcs
## [1] 14
6. Graph-based clustering
# In this case, using the PCs that we chose from getClusteredPCs().
g <- buildSNNGraph(sce, use.dimred="PCAsub")
cluster <- igraph::cluster_walktrap(g)$membership

# Assigning to the 'colLabels' of the 'sce'.
colLabels(sce) <- factor(cluster)
table(colLabels(sce))
## 
##   1   2   3   4   5   6   7   8   9  10  11  12 
##  79 285  64 170 166 164 124  32  57  63  63  24
sce <- runTSNE(sce, dimred="PCAsub")
plotTSNE(sce, colour_by="label", text_by="label")
ratio <- clusterModularity(g, cluster, as.ratio=TRUE)

library(pheatmap)
pheatmap(log10(ratio+1), cluster_cols=FALSE, cluster_rows=FALSE,
    col=rev(heat.colors(100)))
ass.prob <- bootstrapCluster(sce, FUN=function(x) {
    g <- buildSNNGraph(x, use.dimred="PCAsub")
    igraph::cluster_walktrap(g)$membership
}, clusters=sce$cluster)

pheatmap(ass.prob, cluster_cols=FALSE, cluster_rows=FALSE,
    col=colorRampPalette(c("white", "blue"))(100))
subout <- quickSubCluster(sce, groups=colLabels(sce))
table(metadata(subout)$subcluster) # formatted as '<parent>.<subcluster>'
## 
##  1.1  1.2 10.1 10.2 10.3 11.1 11.2   12  2.1  2.2  2.3  2.4  3.1  3.2  3.3  4.1 
##   38   41   16   19   28   29   34   24   96   35   81   73   26   19   19   53 
##  4.2  4.3  4.4  5.1  5.2  6.1  6.2  6.3  7.1  7.2  7.3    8  9.1  9.2 
##   67   33   17   73   93   64   65   35   35   35   54   32   33   24
7. marker基因鉴定
# Uses clustering information from 'colLabels(sce)' by default:
markers <- findMarkers(sce)
markers[[1]][,1:3]
## DataFrame with 20064 rows and 3 columns
##                          Top      p.value          FDR
##                    <integer>    <numeric>    <numeric>
## CPE__chr4                  1  1.72176e-62  1.43939e-59
## KCNQ1OT1__chr11            1  2.07621e-61  1.60220e-58
## LOC100131257__chr7         1  2.66948e-43  7.87654e-41
## PGM5P2__chr9               1  2.67376e-51  1.27730e-48
## SCG2__chr2                 1 1.41986e-104 2.84880e-100
## ...                      ...          ...          ...
## TLX1NB__chr10          19918            1            1
## TNFRSF17__chr16        19946            1            1
## TSPAN32__chr11         19973            1            1
## WFDC11__chr20          20015            1            1
## XKR7__chr20            20025            1  
wmarkers <- findMarkers(sce, test.type="wilcox", direction="up", lfc=1)
wmarkers[[1]][,1:3]
## DataFrame with 20064 rows and 3 columns
##                          Top     p.value         FDR
##                    <integer>   <numeric>   <numeric>
## FBLIM1__chr1               1 7.55507e-30 2.16550e-26
## KCNQ1OT1__chr11            1 1.30379e-37 1.51912e-33
## PGM5P2__chr9               1 1.46543e-35 9.80080e-32
## UGDH-AS1__chr4             1 1.51428e-37 1.51912e-33
## LOC100131257__chr7         2 7.66839e-33 3.07717e-29
## ...                      ...         ...         ...
## TLX1NB__chr10          19918           1           1
## TNFRSF17__chr16        19946           1           1
## TSPAN32__chr11         19973           1           1
## WFDC11__chr20          20015           1           1
## XKR7__chr20            20025           1    
markers <- findMarkers(sce, pval.type="all")
markers[[1]][,1:2]
## DataFrame with 20064 rows and 2 columns
##                        p.value         FDR
##                      <numeric>   <numeric>
## UGDH-AS1__chr4     8.36195e-20 1.67774e-15
## KCNQ1OT1__chr11    2.72694e-19 2.42652e-15
## LOC100131257__chr7 3.62817e-19 2.42652e-15
## TFDP2__chr3        5.98639e-19 3.00277e-15
## LOC643406__chr20   1.09251e-18 4.38402e-15
## ...                        ...         ...
## ZP1__chr11                   1           1
## ZP3__chr7                    1           1
## ZPBP__chr7                   1           1
## ZSCAN1__chr19                1           1
## ZSCAN20__chr1                1           1
8. Detecting correlated genes
# Using the first 200 HVs, which are the most interesting anyway.
# Also turning down the number of iterations for speed.
of.interest <- top.hvgs[1:200]
cor.pairs <- correlatePairs(sce, subset.row=of.interest, iters=1e5)
cor.pairs
## DataFrame with 19900 rows and 6 columns
##                 gene1           gene2         rho     p.value         FDR
##           <character>     <character>   <numeric>   <numeric>   <numeric>
## 1      UGDH-AS1__chr4 KCNQ1OT1__chr11    0.830410 1.99998e-05 3.83241e-05
## 2           GCG__chr2      TTR__chr18    0.798357 1.99998e-05 3.83241e-05
## 3         REG1A__chr2     PRSS1__chr7    0.784339 1.99998e-05 3.83241e-05
## 4         REG1A__chr2    SPINK1__chr5    0.780994 1.99998e-05 3.83241e-05
## 5         REG1A__chr2     REG1B__chr2    0.760322 1.99998e-05 3.83241e-05
## ...               ...             ...         ...         ...         ...
## 19896    TM4SF1__chr3    HYDIN2__chr1 0.000115737     0.99877    0.998971
## 19897   SLC30A8__chr8     MUC13__chr3 0.000169530     0.99919    0.999341
## 19898     KRT7__chr12 FLJ30403__chr19 0.000159983     0.99957    0.999670
## 19899 C15orf48__chr15 FLJ30403__chr19 0.000144531     0.99973    0.999780
## 19900     RBP4__chr10     DUSP1__chr5 0.000153488     0.99993    0.999930
##         limited
##       <logical>
## 1          TRUE
## 2          TRUE
## 3          TRUE
## 4          TRUE
## 5          TRUE
## ...         ...
## 19896     FALSE
## 19897     FALSE
## 19898     FALSE
## 19899     FALSE
## 19900     FALSE
cor.pairs2 <- correlatePairs(sce, subset.row=of.interest, 
    block=sce$donor, iters=1e5)
cor.genes <- correlateGenes(cor.pairs)
cor.genes
## DataFrame with 200 rows and 5 columns
##                gene       rho     p.value         FDR   limited
##         <character> <numeric>   <numeric>   <numeric> <logical>
## 1    UGDH-AS1__chr4  0.830410 7.23629e-05 9.39778e-05      TRUE
## 2         GCG__chr2  0.798357 2.94812e-05 6.17910e-05      TRUE
## 3       REG1A__chr2  0.784339 2.88403e-05 6.17910e-05      TRUE
## 4        TTR__chr18  0.798357 2.72600e-05 6.17910e-05      TRUE
## 5       CHGB__chr20  0.751585 2.70746e-05 6.17910e-05      TRUE
## ...             ...       ...         ...         ...       ...
## 196       FN1__chr2  0.164284 1.59198e-04 1.60806e-04      TRUE
## 197      MAFA__chr8  0.362235 6.12302e-05 8.33063e-05      TRUE
## 198        F3__chr1  0.378165 3.82688e-05 6.31239e-05      TRUE
## 199    SRXN1__chr20  0.340372 2.09472e-04 2.09472e-04      TRUE
## 200 KDM4A-AS1__chr1  0.330622 9.47610e-05 1.03564e-04      TRUE
9. 转换成其他数据形式
y <- convertTo(sce, type="edgeR")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容