處理原始scRNA-seq數據
2.1 FastQC
當你獲取到單細胞下機數據的時候,第一步需要做的就是檢查數據質量。
本次教程使用的數據為(Kolodziejczyk et al. 2015)發表的文章內使用SMART-seq技術做的單細胞測序結果。
示例數據下載地址[1]
ERR522959_1.fastq
和 ERR522959_2.fastq
數據質量查看這里我們推薦使用fastQC。
fastQC是由Babraham Bioinformatics出品的一個軟件,目前是二代測序領域最常用的一個質控軟件,官網點擊[2]
)
2.1.1 安裝
使用conda即可
conda install -c bioconda fastqc
2.1.2 下載數據
wget ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR522/ERR522959/ERR522959_1.fastq.gz
wget ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR522/ERR522959/ERR522959_2.fastq.gz
#查看數據
less ERR522959_1.fastq.gz
2.1.3 生成質量報告
mkdir fastqc_results && fastqc -o fastqc_results ./ERR522959_1.fastq.gz ./ERR522959_2.fastq
# 運行結束后會生成一個html文件和一個gzip文件,打開html文件即可查看質量分析報告
sxj@node5~/scRNA-seq/class/fastqc_results$ll
total 1.6M
drwxr-xr-x 2 sxj users 124 Jul 7 2018 .
drwxr-xr-x 3 sxj users 81 Jul 7 2018 ..
-rw-r--r-- 1 sxj users 340K Jul 7 2018 ERR522959_1_fastqc.html
-rw-r--r-- 1 sxj users 461K Jul 7 2018 ERR522959_1_fastqc.zip
-rw-r--r-- 1 sxj users 337K Jul 7 2018 ERR522959_2_fastqc.html
-rw-r--r-- 1 sxj users 456K Jul 7 2018 ERR522959_2_fastqc.zip
# zip文件打開后和html內容一致的,不再展示
fastqc 報告的具體參數這里不加贅述,請自行理解
2.2 Trimming Reads 清洗數據
本課程使用的處理軟件為Trim Galore!
因為在上一步的報告中我們發現有部分接頭序列,所以這里需要進行數據修剪。
修剪結束以后需要再次使用fastQC生成質量報告查看處理結果。
$mkdir fastqc_trimmed_results && trim_galore --nextera -o fastqc_trimmed_results ./ERR522959_1.fastq.gz ./ERR522959_2.fastq.gz
2.3 File formats 數據格式
FastQ 是大部分最原始scRNASeq的數據,所有的單細胞RNA-seq測序數據都是雙端paired-end測序,barcode序列可能會出現在一個read或者兩個reads內(依據使用protocol的不同),但是使用UMI的方法產生的數據,一個read會包含UMI/barcode/adapters但是由于測序長度原因會不包含轉錄本序列,所以這個方法后續的處理是以單端測序的形式處理的。
FastQ 文件擁有以下的格式:
>ReadID
READ SEQUENCE
+
SEQUENCING QUALITY SCORES
2.3.2 BAM文件格式
BAM文件以一個標準化的高效率的形式存儲了比對后的文件的,BAM文件是由可讀式的SAM文件高效壓縮來的,一般來說會包含一個header(包含樣本準備,測序和比對信息)。
比對文件的標準格式如下
1. QNAME: read name(一般來說可以的話會包含UMI及Barcode信息)
2. FLAG:數值標簽指明比對情況(包括比對到多個位置/單端read匹配等等)
3. RNAME: 比對到的參考基因組
4. POS: 比對到參考基因組的起始位點
5. MAPQ:比對質量
6. CIGAR:字符信息(表明對比的情況,是否有突變缺失插入等)
7. RNEXT:paired-end read 比對到的參考基因組染色體
8. PNEXT:paired-end read 比對到的參考基因組的起始位點
9. TLEN:比對到的長度
10. SEQ: read序列
11. QUAL:read質量
bam文件到sam文件以及sam文件到bam文件的轉換可以通過samtools完成
samtools view -S -b file.sam > file.bam
samtools view -h file.bam > file.sam
很多時候還會有將bam/cram文件轉化為fastq文件的需求,這個可以通過bedtools完成:
# sort reads by name
samtools sort -n original.bam -o sorted_by_name.bam
# remove secondary alignments
samtools view -b -F 256 sorted_by_name.bam -o primary_alignment_only.bam
# convert to fastq
bedtools bamtofastq -i primary_alignment_only.bam -fq read1.fq -fq2 read2.fq
2.3.3 CRAM 文件
CRAM類似于BAM文件,先對比較少見,包含的信息比bam文件少,一般Sanger/EBI的測序結果是這個形式,轉化為fastq文件的時候需要參考基因組。
export REF_CACHE=/path_to/cache_directory_for_reference_genome
samtools view -b -h -T reference_genome.fasta file.cram -o file.bam
samtools view -C -h -T reference_genome.fasta file.bam -o file.cram
2.3.4 手動檢視文件
使用less & more 以及samtools view可以完成對的文件的查看
less file.txt
more file.txt
# counts the number of lines in file.txt
wc -l file.txt
samtools view -h file.[cram/bam] | more
# counts the number of lines in the samtools output
samtools view -h file.[cram/bam] | wc -l
2.3.5 基因組文件的(FASTA, GTF)
為了比對read,我們需要下載參考基因組以及對應的注釋文件。一般來說有以下三個下載來源:
有關差別我在高通量測序數據處理學習記錄(零):NGS分析如何選擇合適的參考基因組和注釋文件這篇文章中有詳細的論述。
另外存有的一個問題就是如果需要往fasta文件和gtf文件內添加內容,我們需要如何操作。(常見的就是ERCC的問題,包括轉入的質粒或者CRISPR相關序列)目前來說沒有標準化的一個方法,我們這里提供了一個Perl腳本完成這個任務。
# Converts the Annotation file from
# https://www.thermofisher.com/order/catalog/product/4456740 to
# gtf and fasta files that can be added to existing genome fasta & gtf files.
my @FASTAlines = ();
my @GTFlines = ();
open (my $ifh, "ERCC_Controls_Annotation.txt") or die $!;
<$ifh>; #header
while (<$ifh>) {
# Do all the important stuff
chomp;
my @record = split(/\t/);
my $sequence = $record[4];
$sequence =~ s/\s+//g; # get rid of any preceeding/tailing white space
$sequence = $sequence."NNNN";
my $name = $record[0];
my $genbank = $record[1];
push(@FASTAlines, ">$name\n$sequence\n");
# is GTF 1 indexed or 0 indexed? -> it is 1 indexed
# + or - strand?
push(@GTFlines, "$name\tERCC\tgene\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
push(@GTFlines, "$name\tERCC\ttranscript\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
push(@GTFlines, "$name\tERCC\texon\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
} close($ifh);
# Write output
open(my $ofh, ">", "ERCC_Controls.fa") or die $!;
foreach my $line (@FASTAlines) {
print $ofh $line;
} close ($ofh);
open($ofh, ">", "ERCC_Controls.gtf") or die $!;
foreach my $line (@GTFlines) {
print $ofh $line;
} close ($ofh);
實際演示
# 腳本保存為ERCC_fasta_gtf_transform.pl
wget https://assets.thermofisher.com/TFS-Assets/LSG/manuals/cms_095047.txt
mv cms_095047.txt ERCC_Controls_Annotation.txt
perl ERCC_fasta_gtf_transform.pl
# 搞定
sxj@node5~/scRNA-seq/class/fastqc_trimmed_results/ERCC$ll
total 224K
drwxr-xr-x 2 sxj users 122 Jul 8 2018 .
drwxr-xr-x 4 sxj users 4.0K Jul 8 2018 ..
-rw-r--r-- 1 sxj users 86K Jul 21 2017 ERCC_Controls_Annotation.txt
-rw-r--r-- 1 sxj users 83K Jul 8 2018 ERCC_Controls.fa
-rw-r--r-- 1 sxj users 43K Jul 8 2018 ERCC_Controls.gtf
-rw-r--r-- 1 sxj users 1.6K Jul 8 02:24 ERCC_fasta_gtf_transform.pl
2.4 Demultiplexing
我不知道該如何翻譯這個詞匯,初步理解為細胞區分或者說是提取barcode/UMI信息,這個過程往往取決于你使用的方法。其中適用性最強的當屬zUMIs,可以提取大部分現有平臺產生數據的barcode/UMI信息。話說回來,現在大部分的數據一般都是整理好返還給你matrix,如果是自己建庫產生的數據,就需要自己寫一個script根據序列信息和位置信息提取對應所需。
對任何數據而言,demultiplexing包括在1-read/2-read確認和移除cell-barcode序列(包括UMI),本篇文章作者貼出了他們使用的perl代碼腳本 publicly available進行一系列的處理。下面的是舉例實戰:
perl 1_Flexible_UMI_Demultiplexing.pl 10cells_read1.fq 10cells_read2.fq "C12U8" 10cells_barcodes.txt 2 Ex
## Doesn't match any cell: 0
## Ambiguous: 0
## Exact Matches: 400
## Contain mismatches: 0
## Input Reads: 400
## Output Reads: 400
## Barcode Structure: 12 bp CellID followed by 8 bp UMI
perl 1_Flexible_FullTranscript_Demultiplexing.pl 10cells_read1.fq 10cells_read2.fq "start" 12 10cells_barcodes.txt 2 Ex
##
## Doesn't match any cell: 0
## Ambiguous: 0
## Exact Matches: 400
## Contain Mismatches: 0
## Input Reads: 400
## Output Reads: 400
對于包含UMI的數據,demultiplexing這一步包括把UMI序列給添加到read name上,如果數據的產生基于droplet技術或者SeqWell技術,將barcode加在read named上也可以避免產生相對較大的數據。
2.4.1 確認包含有細胞的droplets/microwells
基于droplet的建庫方法只有一小部分的droplets既包含bead和一個完成的細胞。實際中會出現RNA污染的問題,破碎的細胞釋放出RNA進入其他的droplet中,和那些正常的droplet一起建庫測序從而導致背景噪音。而droplet的大小,擴增效率,測序的因素等會導致無論是背景噪音還是真實的細胞都會出現建庫大小橫跨較大范圍。目前有不同的方法去鑒別對陣真實細胞的barcode。
大部分的方法都是利用每個barcode含有的轉錄本數量的比例尋找一個“break
point”(或者簡單的指定每個細胞需要包含不低于10個轉錄本),point上游的為大部分的真實細胞和少量的背景,point下游的假設為純背景信息。以下為示例(R語言環境):
# 原始文件
https://github.com/hemberg-lab/scRNA.seq.course/raw/master/droplet_id_example_per_barcode.txt.gz
https://github.com/hemberg-lab/scRNA.seq.course/raw/master/droplet_id_example_truth.gz
# 讀入數據
umi_per_barcode <- read.table("droplet_id_example_per_barcode.txt.gz")
truth <- read.delim("droplet_id_example_truth.gz", sep=",")
# 排序后進行作圖
barcode_rank <- rank(-umi_per_barcode[,2])
plot(barcode_rank, umi_per_barcode[,2], xlim=c(1,8000))
這里我們可以看到有一個指數曲線存在,所以這里log一下讓check point更加突出
log_lib_size <- log10(umi_per_barcode[,2])
plot(barcode_rank, log_lib_size, xlim=c(1,8000))
OK這里明顯更加陡峭了一點,隨后我們就可以根據肉眼來鑒別一下check point在哪或者使用算法來創建重復性較高的check point:
# inflection point
o <- order(barcode_rank)
log_lib_size <- log_lib_size[o]
barcode_rank <- barcode_rank[o]
rawdiff <- diff(log_lib_size)/diff(barcode_rank)
inflection <- which(rawdiff == min(rawdiff[100:length(rawdiff)], na.rm=TRUE))
plot(barcode_rank, log_lib_size, xlim=c(1,8000))
abline(v=inflection, col="red", lwd=2)
# 簡單理解就是算斜率,取一個最大的,那個點就是check point
隨后我們再來檢驗一下檢測到的比例
threshold <- 10^log_lib_size[inflection]
cells <- umi_per_barcode[umi_per_barcode[,2] > threshold,1]
TPR <- sum(cells %in% truth[,1])/length(cells)
Recall <- sum(cells %in% truth[,1])/length(truth[,1])
c(TPR, Recall)
[1] 1.0000000 0.7831707
inflection
[1] 3212
取前3212個細胞,100%的陽性率,78%的檢出率,已經比較可以了。
或者通過建立一個mixture model并且找到check point
set.seed(-92497)
# mixture model
require("mixtools")
## Loading required package: mixtools
## mixtools package, version 1.1.0, Released 2017-03-10
## This package is based upon work supported by the National Science Foundation under Grant No. SES-0518772.
mix <- normalmixEM(log_lib_size)
## number of iterations= 43
plot(mix, which=2, xlab2="log(mol per cell)")
p1 <- dnorm(log_lib_size, mean=mix$mu[1], sd=mix$sigma[1])
p2 <- dnorm(log_lib_size, mean=mix$mu[2], sd=mix$sigma[2])
if (mix$mu[1] < mix$mu[2]) {
split <- min(log_lib_size[p2 > p1])
} else {
split <- min(log_lib_size[p1 > p2])
}
split
[1] 0.7781513
和第一個方法差不多
或者也可以使用固定比例來篩選:
n_cells <- length(truth[,1])
# CellRanger
totals <- umi_per_barcode[,2]
totals <- sort(totals, decreasing = TRUE)
# 99th percentile of top n_cells divided by 10
thresh = totals[round(0.01*n_cells)]/10
plot(totals, xlim=c(1,8000))
abline(h=thresh, col="red", lwd=2)
thresh
[1] 3764.3
作者新開發了一個R包專門來解決這個問題→EmptyDrops, 目前還處于測試版本,可從GitHub上下載使用,它使用X個細胞的全基因表達數據來代表所有的droplets(液滴)同時使用counts數最低的那群droplets作為背景來估計背景"RNA"的表達模式,隨后尋找與背景表達模式相異的那群細胞當作真實檢測到的細胞,這個方法同時結合了一個拐點方法來進行操作,因為背景RNA的表達模式往往和一個群體里面最大那群細胞的表達模式類似。目前來說,EmptyDrops是僅有的一個可以在高差異度樣本里鑒定非常少量細胞barcode的軟件。下面列出測試代碼:
# 下載數據
wget https://github.com/tallulandrews/Tmp/blob/master/droplet_id_example.rds
require("Matrix")
raw.counts <- readRDS("droplet_id_example.rds")
require("DropletUtils")
# emptyDrops
set.seed(100)
e.out <- emptyDrops(my.counts)
is.cell <- e.out$FDR <= 0.01
sum(is.cell, na.rm=TRUE)
plot(e.out$Total, -e.out$LogProb, col=ifelse(is.cell, "red", "black"),
xlab="Total UMI count", ylab="-Log Probability")
cells <- colnames(raw.counts)[is.cell]
TPR <- sum(cells %in% truth[,1])/length(cells)
Recall <- sum(cells %in% truth[,1])/length(truth[,1])
c(TPR, Recall)
2.5 利用STAR進行比對
現在我們已經對reads進行了去除barcode和UMI的處理,下一步的操作就是把序列比對到參考基因組上去,如果我們需要定量基因表達量并且找出哪些基因是特異表達的,我們就需要一些特定的比對工具了。
我們今天主要介紹兩個比對工具,第一個是STAR,我在之前的文章里介紹過高通量測序數據處理學習記錄(一):比對軟件STAR的使用,對于每個測序read,STAR都會找到一個能夠匹配到參考基因組一個或者多個位置上的最長的可能序列。以下圖舉例,我們有一條read(藍色)橫跨兩條外顯子和一個剪切點(紫色)。STAR發現read的第一部分可以匹配到第一個外顯子上,同時read的第二部分可以匹配到第二個外顯子上,由于STAR可以通過這種形式識別剪切事件,所以它也被描述為“剪切感知”比對軟件。
一般來說STAR將一條read比對到參考基因組上,同時也會檢測是否存在新的剪切事件或者染色質易位,這就導致STAR需要很大RAM,尤其是你的參考基因組很大的時候(例如:人類和老鼠)。所以下面演示為了節省時間,我們會使用STAR將read比對到一個只包含2000個轉錄本的的轉錄參考組(注意這在正常情況下是不正常的個)。
STAR的比對需要兩個步驟。在第一個步驟,用戶需要向STAR提交參考基因組序列(FASTA格式)以及注釋文件(GTF文件),STAR會依據此構建索引(index),第二步,STAR會將reads比對到索引上(index)。
今天我們只比對2000個轉錄組的數據而不是一整個參考基因組,可以從ensembl上獲取很多模式生物的
參考基因組。構建索引的代碼如下:
# download data
wget https://github.com/hemberg-lab/scRNA.seq.course/raw/master/2000_reference.transcripts.fa
mkdir indices
mkdir indices/STAR
STAR --runThreadN 4 --runMode genomeGenerate --genomeDir indices/STAR --genomeFastaFiles Share/2000_reference.transcripts.fa
隨后進行比對:
mkdir results
mkdir results/STAR
STAR --runThreadN 4 --genomeDir indices/STAR --readFilesIn Share/ERR522959_1.fastq Share/ERR522959_2.fastq --outFileNamePrefix results/STAR/
學習任務:
- 閱讀STAR manual進行命令學習
- 如果我們基于整個基因組創建索引的時候,命令會有什么區別
- 學習理解比對參數
- 嘗試著去理解比對后的結果和報告
2.6 Kallisto 和 Pseudo-Alignment
STAR是一個基于reads的比對工具,而Kallisto則是一個pseudo-aligner(偽比對工具——翻譯不全面,請自行理解) Bray et al. 2016[3]。而STAR和Kallisto的區別在于,STAR直接比對reads到參考基因組上而Kallisto則是將k-mers比對到參考基因組上。
2.6.1 什么是k-mer?
k-mer就是用一個read提取的長度為k的序列,舉例來說,想象我們現在擁有一個read序列為ATCCCGGGTTAT并且我們想要基于此創造7-mers。我們會依次隔一個base選取長度為7的序列。示意如圖二:2.6.2為什么是比對k-mers而不是reads?
主要有兩個原因:
- Pseudo-aligners利用k-mers和一個巧妙的計算方法可以更快的完成比對。如果你對算法有興趣,詳情請參考文獻:Bray et al., 2017
- 在某些條件下,pseudo-aligners可以比傳統的比對軟件更好的處理測序錯誤,想象假如我們在序列的第一個堿基擁有一個錯誤,它會影響第一個7-mer而不是影響后面的7-mers。
2.6.3 Kallisto的pseudo模式
Kallisto貼心的專門為單細胞測序數據準備了一個特殊模式。不像STAR,Kallisto的pseudo模式會將k-mers比對到轉錄組上而不是基因組上,這就意味著的Kallisto會將reads比對到剪切異構體上而不是基因上,比對到異構體上而不是基因上對于單細胞RNA-seq是很有挑戰性的,原因如下:
- 單細胞RNA-seq的覆蓋度比bulk RNA-seq要低,意味著從reads上可以獲取的信息量減少了
- 許多RNA-seq技術擁有3' 端覆蓋度的偏向性,這就意味著如果兩個異構體只是在他們的5'端有差異的話,就不大可能判斷read來源于哪條異構體。
- 一些單細胞測序方法的reads的讀長比較短,也意味著很難通過較短的序列信息判斷來源于哪個異構體
Kallisto的pseudo模式采取了一種略微區別于pseudo-alinment的方法。它將reads歸類于某個異構體,而是將其歸類于equivalence classes(等價類)。這就意味著假如一個read可以比對到多個異構體上,Kallisto會記錄這個read到包含這幾個異構體的equivalence classes里面,下游的分析也就區別于利用基因或者異構體的分析,而是以equivalence classes取代之。圖三展示了比對原理:
今天的演示教程是對一個細胞的測序結果進行比對,但Kallisto可以通多對多細胞數據(也就是多批的單細胞數據)進行比對,詳細的參數可見Manual。
就像STAR一樣,你也需要在比對前為Kaliisto構建索引(index)。代碼如下:
mkdir indices/Kallisto
kallisto index -i indices/Kallisto/transcripts.idx Share/2000_reference.transcripts.fa
TASK:閱讀manual文檔學習如何使用pseudo模式進行比對并進行實戰操作。
2.6.4 Ksllisto Pseudo模式的比對
比對可見如下代碼:
mkdir results/Kallisto
kallisto pseudo -i indices/Kallisto/transcripts.idx -o results/Kallisto -b batch.txt
index文件為上一步所創立,batch文件格式如下:
#id file1 file 2
cell1 cell1_1.fastq.gz cell1_1.fastq.gz
cell2 cell2_1.fastq.gz cell2_1.fastq.gz
cell3 cell3_1.fastq.gz cell3_1.fastq.gz
...
“#” 號所在的一行將會被忽略,第一列為cell id, 后兩列為雙端測序文件,如果加入
single
參數就只需要提供一個文件
--umi
參數被指定的時候,batch文件的格式為:
#id umi-file file-1
cell1 cell_1.umi cell_1.fastq.gz
cell2 cell_2.umi cell_2.fastq.gz
cell3 cell_3.umi cell_3.fastq.gz
...
其中umi文件的內容格式為:
TTACACTGAC
CCACTCTATG
CAGGAAATCG
...
需要注意的是,umi的順序需要和fastq文件里面的reads順序一致。
2.6.5 Kallisto Pseudo-Alignment比對結果的解讀
上述的命令會產生四個文件:
- matrix.cells
- 包含一系列的細胞ID
- matrix.ec
- 包含比對過程中使用過的equivalence classes,每一行的第一個數字是class ID, 以“10 1,2,3”舉例, 其代表的意思為,class 10包含有轉錄本ID 1,2和3。ID的序號對應著轉錄本在參考基因組上出現的順序。需要注意的是,這里使用的是0-based的計數形式,也就是說ID 1,2,3對應的是2,3,4號轉錄本。
- matrix.tsv
- 包含每個細胞里面比對到對應equivalence classes上的read數目,第一個數字為equivalence classes class ID(與matrix.ec匹配),第二個數字為細胞DI,對應matrix.cells文件,第三個數字就是該細胞比對到該class的read數目。以“5 1 3”舉例,其代表的意思為細胞1號中有3個reads比對到第5類equivalence classes上,這里同樣使用的是0-based的計數形式,也就是說細胞1號對應著matrix.cells文件第二行的信息。
- run_info.json
- 包含運行信息,可以忽略。
參考文獻
-
Kolodziejczyk, Aleksandra A., Jong Kyoung Kim, Valentine Svensson, John C. Marioni, and Sarah A. Teichmann. 2015. “The Technology and Biology of Single-Cell RNA Sequencing.” Molecular Cell 58 (4). Elsevier BV: 610–20. doi:10.1016/j.molcel.2015.04.005. ?
-
babraham.ac.uk ?
-
Bray, Nicolas L, Harold Pimentel, Páll Melsted, and Lior Pachter. 2016. “Near-Optimal Probabilistic Rna-Seq Quantification.” Nat Biotechnol 34 (5): 525–27. doi:10.1038/nbt.3519. ?