系统学习单细胞转录组测序scRNA-Seq(四)

刘小泽写于19.3.26
陌生的领域就像一张白纸,怎么画就看自己了

前言

关于单细胞测序,我们已经知道了它和bulk RNA-seq的区别,简单说就是scRNA体现异质性(个体),bulk体现平均程度(总体),因此利用bulk RNA不能区分一个样本中的不同细胞类型

scRNA&bulk RNAseq

做scRNA的最大的好处就是可以"对症下药"(当然这也是最理想的情况=》什么细胞配合什么种类或者剂量的药物)

对症下药(图片来自:https://stm.sciencemag.org/content/9/408/eaan4730.full)

BiomarkerA biological molecule found in blood, other body fluids, or tissues that is a sign of a normal or abnormal process, or of a condition or disease. A biomarker may be used to see how well the body responds to a treatment for a disease or condition. Also called molecular marker and signature molecule.

一般在下机后会得到一个表达矩阵,行为基因,列为细胞样本(根据测序平台不同细胞数不同,目前商业化平台有10X和BD,一般都能达到2000-8000细胞量,可以覆盖绝大部分组织的single cell群体类型)。
还包括两个协变量(covariates:解释变量,不为实验者所操纵,但仍影响实验结果):gene-level(比如GC含量)和cell-level(比如细胞测序的批次信息)。

单细胞和bulk转录组表达矩阵主要有两点不同:

  • bulk的表达矩阵是reads比对到基因的数目;单细胞的表达矩阵是reads比对到某个细胞的某个基因的数目(barcode用来区分细胞;UMI用来区分转录本/基因)

  • 单细胞存在许多的0,有两个可能:第一种是真的基因在细胞中不表达(参与细胞分化的基因并不是在每个cell cycle都表达);第二种是技术误差,基因实际表达但测序没有测到(也就是"dropouts")

从头开始慢慢理解

这一部分暂时不讨论细节,先看Big Picture

探索表达矩阵

The matrix of counts is the number of sequenced reads aligned to each gene and each sample

假设这个矩阵有10个基因(Lamp5, Fam19a1, Cnr1, Rorb, Sparcl1, Crym, Ddah1, Lmo3, Serpine2, Pde1a) 和5个细胞样本(SRR2140028, SRR2140022, SRR2140055, SRR2140083, SRR2139991)

表达矩阵如下:

> counts
         SRR2140028 SRR2140022 SRR2140055 SRR2140083 SRR2139991
Lamp5            10         11          0          0          8
Fam19a1          11          9          0          6          0
Cnr1              0          0          0         12          0
Rorb              0          8          0          0          0
Sparcl1           0          7          0         13          0
Crym              8          9         10         12          5
Ddah1            16          0          0          8          0
Lmo3              0          0          8         13          0
Serpine2          8          0          0          0          0
Pde1a             0         14          8         11          0
# head of count matrix
counts[1:3, 1:3]

# count of specific gene and cell
reads <- counts["Cnr1", "SRR2140055"]

# overall proportion of zero counts 
pZero <- mean(counts==0)

# cell library size
libsize <- colSums(counts)

The cell coverage is the average number of expressed genes that are greater than zero in each cell.

目的:ggplot2画出cell coverage

假设目前有一个关于细胞样本的协变量(cell-level),内容如下:

> cell_info
                names batch patient 
SRR2140028 SRR2140028     1       a      
SRR2140022 SRR2140022     1       a     
SRR2140055 SRR2140055     2       b     
SRR2140083 SRR2140083     2       c     
SRR2139991 SRR2139991     2       c      

先计算coverage,然后加在cell_info的最后

# find cell coverage 计算count大于0的平均值
# 先将表达量为0的值赋值一个NA,然后计算时忽略掉它们
is.na(counts)=counts==0
coverage <- colMeans(counts,na.rm=T)

cell_info$coverage <- coverage
library(ggplot2)
ggplot(cell_info, aes(x = names, y = coverage)) + 
  geom_point() +
  ggtitle('Cell Coverage') + 
  xlab('Cell Name') + 
  ylab('Coverage')

看看大体的流程

测序=》single cell 发展历史

图片来自:Exponential scaling of single-cell RNA-seq in the past decade. (2018 Nature Protocols)

2009-2017不到十年,已报道的细胞研究数目就从1个飞跃至一百万个

scRNA发展

尽管这些方法各不相同,但原理的主要不同之处有两个:分子定量(Quantification)和捕获方法(Capture)

  • RNA分子定量(Quantification):主要是两种技术(full-length和tag-based)
    The full-length:基于全长,试图获取每个转录本覆盖度一致且独特的全长片段;
    The tag-based:基于标签探针,捕获RNA的5'或3'端序列
  • 捕获方法(Capture):不仅决定了细胞的筛选方式以及实验的通量,同时也间接反映了测序外的其他信息。目前主要有三种捕获方法:
    微孔 microwell
    微流 microfluidic
    微滴 droplet

详细看这里:https://hemberg-lab.github.io/scRNA.seq.course/introduction-to-single-cell-rna-seq.html

目前两大商业化单细胞测序公司:

10X Genomics Chromium
利用微流控油滴包裹barcode标记实现高通量细胞捕获和标记,一次最多捕获8万细胞。特点就是:细胞通量高建库成本低捕获周期短
主要用于细胞分型标记因子的鉴定,从而实现对细胞群体的划分与细胞群体间基因表达差异的检测,此外该技术还可以预测细胞分化与研究发育轨
迹。

BD Rhapsody
基于微孔平台,通过刚性磁珠进行单细胞捕获(捕获后磁珠可以保存3个月以上);利用成像系统对单细胞分离进行质控。特点是:细胞样本损伤小;质控可视化,监控双细胞比例;细胞捕获较稳定;可以结合蛋白表达量分析转录组;可以设计panel分析特定基因

质控

目的就是减少技术误差,去掉有问题的细胞,一般反映细胞是否有问题主要看两个方面:

  • library size:能比对到每个细胞的总reads数(一个ibrary指一个细胞)
  • cell coverage:每个细胞中表达基因的平均数
标准Workflow

来自:Bioconductor workflow for single-cell RNA sequencing

可以从下图看到:

第一步就是基因和细胞层次的标准化(normalization):消除与研究无关的生物和技术影响;

第二步是降维,基因数量决定维度,需要从J个基因降到K个基因,实现了两个事情,一是维度降低可以更好掌控数据,二是保留感兴趣的特征同时减少了背景噪音;

第三步是聚类分群,按照降维后的矩阵(K x N,N是细胞数量),这一步给了每个细胞一个cluster number;

第四步是差异分析,找到biomarker,也就是两组细胞的表达差异基因

workflow

慢慢翻开细枝末节

加载、创建、获取single-cell数据集

单细胞分析利用的几个包都是高度整合的,里面需要用到许多S4对象,只有理解好这些对象才能看懂分析流程

首先了解一下SingleCellExperiment对象

介绍:

https://www.bioconductor.org/packages/devel/bioc/vignettes/SingleCellExperiment/inst/doc/intro.html

SingleCellExperiment(SCE)是一个S4对象,作者是Davide Risso and Aaron Lun 。官网称它是light-weight container for single-cell genomics data ,看出它是一个容器,可以装单细胞组学数据。那么就知道和我们日常接触的一般表达矩阵不同,它肯定还包含一些表型信息(对象Object 简单理解就是:包含多个数据框、矩阵或者列表,用到哪个提取哪个。数据框取子集我们用$,对象取子集我们要用@)

之前知道了单细胞数据一般有三个矩阵(表达矩阵raw counts、协变量信息gene-level & cell-level metadata),这个对象就可以将这三个同时存储在一个容器中,另外还有一些其他重要信息,比如:spike-in info,dimentionality reduction coordinates,size factors for each cell

下载、加载包

if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
BiocManager::install("SingleCellExperiment", version = "3.8")
library(SingleCellExperiment)
创建对象

三个要素:表达矩阵、行名、列名

> # 先设计矩阵(假设counts值服从泊松分布)
> counts <- matrix(rpois(8,lambda = 10),ncol = 2,nrow = 4)
> rownames(counts) <- c("Lamp5","Fam19a1","Cnr1","Rorb")
> colnames(counts) <- c("SRR2140021","SRR2140023")
> counts
        SRR2140021 SRR2140023
Lamp5            4          6
Fam19a1          9         13
Cnr1            14          5
Rorb            15          7

# 创建对象第一种方法
#第一个参数assays就是取表达矩阵的list
> sce <- SingleCellExperiment(assays = list(counts = counts),
+                             rowData = data.frame(gene = rownames(counts)),
+                             colData = data.frame(cell = colnames(counts)))
> sce
class: SingleCellExperiment 
dim: 4 2 
metadata(0):
assays(1): counts
rownames(4): Lamp5 Fam19a1 Cnr1 Rorb
rowData names(1): gene
colnames(2): SRR2140021 SRR2140023
colData names(1): cell
reducedDimNames(0):
spikeNames(0):

# 创建对象第二种方法(先构建bulk RNA的一个对象SummarizedExperiment,然后转换格式)
> se <- SummarizedExperiment(assays = list(counts = counts))
# as =》 Force an Object to Belong to a Class 
> sce <- as(se,"SingleCellExperiment")
上面都是自己创造的模拟数据集,下面看一个真的数据集

来自:Adult mouse cortical cell taxonomy revealed by single cell transcriptomics(2016,Nature Neuroscience)

library(scRNAseq);data(allen)
# 其中包含了379个成年雄性小鼠不同神经元的视觉皮层细胞数据
# allen数据集是一个SummarizedExperiment对象,需要先转换
> sce <- as(allen,"SingleCellExperiment")
> sce
class: SingleCellExperiment 
dim: 20908 379 
metadata(2): SuppInfo which_qc
assays(4): tophat_counts
  cufflinks_fpkm rsem_counts
  rsem_tpm
rownames(20908): 0610007P14Rik
  0610009B22Rik ... Zzef1 Zzz3
rowData names(0):
colnames(379): SRR2140028
  SRR2140022 ... SRR2139341
  SRR2139336
colData names(22): NREADS
  NALIGNED ... Animal.ID
  passes_qc_checks_s
reducedDimNames(0):
spikeNames(0):
# size factors
> sizeFactors(sce) <- colSums(assay(sce))

质控

目的:get out of technical issues and biases

利用的数据集来自:Batch effects and the effective design of single-cell gene expression studies. (2017, Tung et al. )

6 RNA-sequencing datasets per individual : 3 bulk & 3 single-cell (on C1 plates) and each dataset was sequenced in a different batch【Fluidigm C1 platform的低通量的微流控技术,能在捕获细胞时可视化的控制empty wells or doublets】

Three C1 96 well-integrated fluidic circuit (IFC) replicates were collected from each of the three Yoruba individuals.

表达矩阵下载:ftp://ftp.ncbi.nlm.nih.gov/geo/series/GSE77nnn/GSE77288/suppl/GSE77288_reads-raw-single-per-sample.txt.gz

library("data.table")
library("dplyr")
reads_raw <- fread("GSE77288_reads-raw-single-per-sample.txt")
setDF(reads_raw)
dim(reads_raw)
# 得到metadata
anno <- reads_raw %>%
    select(individual:well) %>%
    mutate(batch = paste(individual, replicate, sep = "."),
           sample_id = paste(batch, well, sep = "."))
head(anno)
dim(anno)
# 得到表达矩阵
reads <- reads_raw %>%
    select(starts_with("ENSG"), starts_with("ERCC")) %>%
    t
colnames(reads) <- anno$sample_id
reads[1:5, 1:5]
dim(reads)
# 构建对象
sce <- SingleCellExperiment(assays = list(counts = reads),
                            rowData = data.frame(gene = rownames(reads)),
                            colData = anno)

# 去掉样本中表达量均为0的基因
sce2 <- sce[apply(counts(sce), 1, sum) >0,]
dim(sce);dim(sce2)#大约1700个基因不表达
# 添加Spike信息
isSpike(sce2, "ERCC") <- grepl("^ERCC-", rownames(sce2))

> sce2
class: SingleCellExperiment 
dim: 18726 864 
metadata(0):
assays(1): counts
rownames(18726): ENSG00000237683 ENSG00000187634 ... ERCC-00170
  ERCC-00171
rowData names(9): gene is_feature_control ... total_counts
  log10_total_counts
colnames(864): NA19098.r1.A01 NA19098.r1.A02 ... NA19239.r3.H11
  NA19239.r3.H12
colData names(41): individual replicate ...
  pct_counts_in_top_200_features_ERCC
  pct_counts_in_top_500_features_ERCC
reducedDimNames(0):
spikeNames(1): ERCC

# Calculate QC metrics
library(scater)
# 常用的feature control:such as ERCC spike-in sets or mitochondrial genes
sce2 <- calculateQCMetrics(sce2, feature_controls = list(ERCC = isSpike(sce2, "ERCC")))
# 结果会在colData这一部分增加许多列,帮助过滤低表达基因和样本
names(colData(sce2))

进行简单的细胞过滤:可以根据文库大小(Library size)和批次(Batch)进行

# 1.Filter cells with Library size
# 设置阈值(文库大小基本在2M reads以上,可以设置文库大小的5%作为过滤)
# 阈值的设定没有固定标准,需要考虑具体数据集
threshold <- 100000
# 画密度图
plot(density(sce2$total_counts), main = 'Density - total_counts')
abline(v = threshold)
# 要保留的细胞
keep <- sce2$total_counts > threshold
# 统计过滤信息
table(keep)

FALSE  TRUE 
    6   858 

# 2.Filter cells with Batch[结果见下图]
# 方法一:
cDataFrame <- as.data.frame(colData(sce2))
# plot cell data
ggplot(cDataFrame, aes(x = total_counts, y = total_counts_ERCC, col = batch)) + 
    geom_point()
# 方法二:
plotColData(
    sce2,
    y = "total_counts_ERCC",
    x = "total_counts",
    colour_by = "batch")
# 要保留的细胞
> keep <- sce$batch != "NA19098.r2"
> table(keep)
keep
FALSE  TRUE 
   96   768 

下图中,x轴是total counts,y轴是仅有ERCC基因的total counts,每个点代表一个细胞,细胞根据批次上色。

可以看到橙色点(r2)的ERCC占比更高,这个批次在原文中也体现出来了,和其他batch非常不同

ERCC是已知序列和数量的合成mRNA,RNA的读数将提供样本间差异的信息。spike-in control 在确定测序过程中的empty Wells和的dead cells有重要作用,高的ERCC含量与低质量数据相关,并且通常是排除的标准。

Filter cells with Batch

细胞过滤后,然后进行基因过滤 (因为有的基因虽然表达,但是却是在被过滤掉的细胞中,因此也算作无效)

目的就是保留至少在1个细胞中表达量不为0

filter_genes <- apply(counts(sce2), 1, function(x){
    length(x[x >= 1]) >= 1
})
table(filter_genes)
# 虽然这里不存在低表达基因

下次开始标准化


欢迎关注我们的公众号~_~  
我们是两个农转生信的小硕,打造生信星球,想让它成为一个不拽术语、通俗易懂的生信知识平台。需要帮助或提出意见请后台留言或发送邮件到jieandze1314@gmail.com

Welcome to our bioinfoplanet!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270