开心回归~复习下之前的学习内容

刘小泽写于18.11.12 半年之前我和花花成立了“生信星球”,转眼过得好快,我们每天都能和爱生信的小伙伴们交流,还办了9期培训,灰常开心

终于可以回归写推送了,连续半个月奋战两篇文章,好累,真不如学知识写推送轻松。时隔半月,有点忘记,但是重新学一次,又能学到新知识,还是不错的

数据准备:

数据地址在 http://www.ncbi.nlm.nih.gov/geo/download/?acc=GSE63310&format=file

files <- c("GSE63310_RAW/GSM1545535_10_6_5_11.txt", 
           "GSE63310_RAW/GSM1545536_9_6_5_11.txt",
           "GSE63310_RAW/GSM1545538_purep53.txt",
           "GSE63310_RAW/GSM1545539_JMS8-2.txt",
           "GSE63310_RAW/GSM1545540_JMS8-3.txt",
           "GSE63310_RAW/GSM1545541_JMS8-4.txt",
           "GSE63310_RAW/GSM1545542_JMS8-5.txt",
           "GSE63310_RAW/GSM1545544_JMS9-P7c.txt", 
           "GSE63310_RAW/GSM1545545_JMS9-P8c.txt")
# 读取第一个文件,看下前5行
read.delim(files[1], nrow=5)
#>    EntrezID GeneLength Count
#> 1    497097       3634     1
#> 2 100503874       3259     0
#> 3 100038431       1634     0
#> 4     19888       9747     0
#> 5     20671       3130     1

批量读取+转换:

  • 方法一:一次性读取全部,用readDGE函数
suppressMessages(library(limma))
suppressMessages(library(edgeR))
#输入基因名和count的列
x <- readDGE(files, columns = c(1,3)) 
# x包含了两部分信息:sample和count
class(x)
#> [1] "DGEList"
#> attr(,"package")
#> [1] "edgeR"
dim(x)
#> [1] 27179     9
  • 方法二:分别读取,再用DGEList函数转换全部

转换下样本信息

存储样本与cell type(basal,LP,ML)/ genotype(wild-type, knockout)/ phenotype(status, sex, age)/
sample treatment(drug, control)/ batch effect (date, lane)

# 输入start、stop 位置
samplenames <- substring(colnames(x), 25, nchar(colnames(x))) 
samplenames
#> [1] "10_6_5_11" "9_6_5_11"  "purep53"   "JMS8-2"    "JMS8-3"    "JMS8-4"   
#> [7] "JMS8-5"    "JMS9-P7c"  "JMS9-P8c"
#去掉列名的重复项,重新命名
colnames(x) <- samplenames 
#添加分组信息,比如细胞类型
group <- as.factor(c("LP", "ML", "Basal", "Basal", "ML", "LP",
"Basal", "ML", "LP"))
x$samples$group <- group
# 添加lane信息
lane <- as.factor(rep(c("L004","L006","L008"), c(3,4,2))) 
x$samples$lane <- lane
x$samples
#>                                           files group lib.size
#> 10_6_5_11 GSE63310_RAW/GSM1545535_10_6_5_11.txt    LP 32863052
#> 9_6_5_11   GSE63310_RAW/GSM1545536_9_6_5_11.txt    ML 35335491
#> purep53     GSE63310_RAW/GSM1545538_purep53.txt Basal 57160817
#> JMS8-2       GSE63310_RAW/GSM1545539_JMS8-2.txt Basal 51368625
#> JMS8-3       GSE63310_RAW/GSM1545540_JMS8-3.txt    ML 75795034
#> JMS8-4       GSE63310_RAW/GSM1545541_JMS8-4.txt    LP 60517657
#> JMS8-5       GSE63310_RAW/GSM1545542_JMS8-5.txt Basal 55086324
#> JMS9-P7c   GSE63310_RAW/GSM1545544_JMS9-P7c.txt    ML 21311068
#> JMS9-P8c   GSE63310_RAW/GSM1545545_JMS9-P8c.txt    LP 19958838
#>           norm.factors lane
#> 10_6_5_11            1 L004
#> 9_6_5_11             1 L004
#> purep53              1 L004
#> JMS8-2               1 L006
#> JMS8-3               1 L006
#> JMS8-4               1 L006
#> JMS8-5               1 L006
#> JMS9-P7c             1 L008
#> JMS9-P8c             1 L008

增加一个基因注释信息

基因注释涉及到ID转换,方法一:clusterProfiler

# 数据集中使用的是EntrezID
suppressMessages(library(Mus.musculus, supr))
suppressMessages(library(clusterProfiler))
geneid <- rownames(x)
# 但是好像没有染色体信息
genes <- bitr(geneid, OrgDb = Mus.musculus, fromType = "ENTREZID", toType = "SYMBOL" )
#> 'select()' returned 1:1 mapping between keys and columns
#> Warning in bitr(geneid, OrgDb = Mus.musculus, fromType = "ENTREZID", toType
#> = "SYMBOL"): 3.52% of input gene IDs are fail to map...
head(genes)
#>    ENTREZID  SYMBOL
#> 1    497097    Xkr4
#> 2 100503874 Gm19938
#> 3 100038431 Gm10568
#> 4     19888     Rp1
#> 5     20671   Sox17
#> 6     27395  Mrpl15

方法二:biomaRt(属于Ensembl)

suppressMessages(library(Mus.musculus))
geneid <- rownames(x)
# 增加Symbol名称和染色体信息
genes <- select(Mus.musculus, keys=geneid, 
                columns=c("SYMBOL", "TXCHROM"),keytype="ENTREZID")
#> 'select()' returned 1:many mapping between keys and columns
head(genes)
#>    ENTREZID  SYMBOL TXCHROM
#> 1    497097    Xkr4    chr1
#> 2 100503874 Gm19938    
#> 3 100038431 Gm10568    
#> 4     19888     Rp1    chr1
#> 5     20671   Sox17    chr1
#> 6     27395  Mrpl15    chr1

需要注意的是:ID转换中可能出现多个同样的Entrez ID,比如某个基因出现在不同染色体,
就会在不同位置出现同一个ID。这种情况需要先检查下

dup <- genes$ENTREZID[duplicated(genes$ENTREZID)]
genes[genes$ENTREZID %in% dup,][1:10,]
#>        ENTREZID    SYMBOL TXCHROM
#> 5360  100316809 Mir1906-1   chr12
#> 5361  100316809 Mir1906-1    chrX
#> 9563      12228      Btg3   chr16
#> 9564      12228      Btg3   chr17
#> 11350    433182     Eno1b    chr4
#> 11351    433182     Eno1b   chr18
#> 11543 100217457  Snord58b   chr14
#> 11544 100217457  Snord58b   chr18
#> 13226    735274  Mir684-1    chr2
#> 13227    735274  Mir684-1    chr5
# 出现多次的基因只统计出现第一次的,得到的是一个位置向量,即位于多少行
mat <- match(geneid, genes$ENTREZID)
genes <- genes[mat,]
#再次验证
genes[genes$ENTREZID %in% dup,][1:5,]
#>        ENTREZID    SYMBOL TXCHROM
#> 5360  100316809 Mir1906-1   chr12
#> 9563      12228      Btg3   chr16
#> 11350    433182     Eno1b    chr4
#> 11543 100217457  Snord58b   chr14
#> 13226    735274  Mir684-1    chr2
x$genes <- genes

数据预处理

raw-count标准化

不管是差异分析还是其他用到count值的相关分析,如WGCNA,都基本不直接用原始count值,原因是这个数值容易受到外界的干扰。一般来讲,影响raw count的有两个因素:

  • 测序深度
    这个比较好理解,深度越大,得到的reads数就越多,当然count差异就越大
  • RNA的组织/时间特异性
    不同时期基因表达量是不一样的,很难保证两组样本中RNA是同一时期的

因此需要先对测序深度做一个转换,也就是所谓的“标准化”,减少外在影响

比较流行的标准化方式有:counts per million (CPM), log2-counts per million (log-CPM), reads per kilobase of transcript per million (RPKM), fragments per kilobase of transcript per million (FPKM); 其中CPM与logCPM没有考虑基因长度(要求略低),直接对矩阵进行转换。

# edegR中的CPM与log-CPM
cpm <- cpm(x)
lcpm <- cpm(x, log=TRUE)
# 如果用edegR中的rpkm,需要提供gene length信息
# 用TMM方法
x <- calcNormFactors(x, method = "TMM")

去掉不表达基因

所有的表达量数据都存在表达与非表达基因,拿到表达量数据先看下非表达基因占多少。

#这里有9组样本,因此可以统计9组中表达量都为0的基因
table(rowSums(x$counts==0)==9)
#> 
#> FALSE  TRUE 
#> 22026  5153

基因必须至少在一组处理中或者任意3个样本中有表达量才能被保留。当然,非表达的需要去除,以减少后续分析压力

keep.exprs <- rowSums(cpm>1)>=3
# 行代表基因,列代表样本;这里选择全部样本
x <- x[keep.exprs,, keep.lib.sizes=FALSE]
dim(x)
#> [1] 14165     9

基因表达分布的标准化

使用trimmed mean of M-values(TMM),也就是目前认为最准确的标准化方式
为了解决样本间由于组织、时间特异性而引起的误差,TMM首先从所有样本中挑选一个样本作为参照,当对其他样本进行归一化时,就只考虑参照样本和待归一化的样本间共有的RNA
一般来讲,mRNA数据使用TMM就可以【但是单细胞测序及全转录组一般是不行的,因为它们的差异表达比较多】

x <- calcNormFactors(x, method = "TMM")

非监督式样本聚类

在正式开始差异分析之前,可以使用非监督式学习处理一下:

什么是非监督?

将数据按相似度聚类(clustering)成不同的分组或者用降维的方式,保留基本的数据结构,同时压缩数据。包含了K 均值聚类、层次聚类、主成分分析(PCA)和奇异值分解(SVD)

  • K均值聚类
    目标是将数据点分组,让不同聚类中的数据点不同,同一聚类中的数据点类似;使用这种方法希望结果的数据点被聚类为 K 组。K 大分组就小,就有更多粒度;K 小时,分组就大,粒度更少(可以理解成零散程度)

比如一个领导者一般气场比较大,周围会有一些像被吸附了的帮手;如果这样的领导只有一个,那么群众们都围着他转;如果英雄辈出,那么各自会形成一个小中心圈,分别集结一小帮人

  • 层次聚类
    我们日常说的“做个聚类树”,就是指的这个。目标是构建一个树状层次,让相似的离得更近。它是这么做的:
  1. 先从 第N 个聚类开始,每个数据点一个聚类;
  2. 将彼此靠得最近的两个聚类融合为一个,那么现在有 N-1 个聚类
  3. 重新计算这些聚类之间的距离(方法很多,其中一种“average-linkage clustering”将两个聚类之间的距离看作是聚类中元素所有距离的平均值)
  4. 重复2-3,再选择聚类的数量(就是要将整体分成几部分),画条水平线
  • 降维
    两种办法:主成分分析和奇异值分解
  1. 主成分分析:假设我们现在有1w维空间的数据,然后怎么样才能知道数据间的联系呢,哪些比较强势?我们可以将原始数据映射到另一个更紧凑的空间中(比如只有100维),减少了复杂度(也就是维度),还保证了原始结构不变(即方差不变)
  2. 奇异值分解(SVD)
    如果说我们的数据是一个a X b的大型矩阵,通过SVD将大矩阵拆分成几个小矩阵的乘积,从中找一个对角矩阵叫做“奇异值”,之所以奇异,是因为它可以用于压缩原来的矩阵。如果我们丢弃奇异值中最小的 20% 以及其他矩阵中相关的列,我们就可以节省大量空间,并能很好地表示原来的矩阵
这里怎么做?

这里采用limma的multidimensional scaling (MDS) plot即“多维尺度变换”,这个会用非监督式显示样本之间的异同,在正式差异分析前帮助我们判断潜在的差异样本。它的结果会将所有样本划分成几个维度,第一维度的样本代表了最大的差异,维度越往后,相似度就越大,差异分析的结果越不理想

当实验设计中存在多个实验因子时,每个实验因子都要进行这几个维度的检测。这样做,还能看出哪个实验因子对差异表达的贡献最大,基本没什么影响的因子,就无法参与后续分析。

suppressMessages(library(RColorBrewer))
# 这里就用最简单的CPM值
lcpm <- cpm(x, log=TRUE)
par(mfrow=c(1,2))
col.group <- group
levels(col.group) <- brewer.pal(nlevels(col.group), "Set1") 
col.group <- as.character(col.group)
col.lane <- lane
levels(col.lane) <- brewer.pal(nlevels(col.lane), "Set2") 
col.lane <- as.character(col.lane)
# 1、2维度
plotMDS(lcpm, labels=group, col=col.group) 
title(main="A. Sample groups")
# 3、4维度
plotMDS(lcpm, labels=lane, col=col.lane, dim=c(3,4)) 
title(main="B. Sequencing lanes")

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

Welcome to our bioinfoplanet!

你可能感兴趣的:(开心回归~复习下之前的学习内容)