day53 三组转录组数据分析

学习及参考教程:
https://mp.weixin.qq.com/s/uLt-bYCdVcBH6mqoIG_r6w这个教程里面有个别地方不太合理,所以调整并备注了一些命令函数的意义,以备后面复习或调用。
https://www.jianshu.com/p/f994631684b0

文中实验检测了三组数据,WT,AI和Y19F,每组3个样本。所以一共有9个counts数据。直接下载counts数据,在windows系统的R里面进行下面分析。先整体分析,后分别把AI和Y19F,与WT比较。然后看AIvsWT与Y19Fvs WT两种比对的交集,共性特性。

一、读入及格式转换

#先安装一些之前没有的包:
install.packages("FactoMineR")   #用来分析PCA或MCA等
install.packages("factoextra")  #用来可视化
install.packages("tidyverse") #一个基础包,含有ggplot2、dplyr。。很常用
install.packages("pheatmap")
install.packages("VennDiagram")
#清理变量加载各种包
rm(list = ls())
setwd("D:/work/NGSanalysis/rnaseq")
library(edgeR) 
library(clusterProfiler)
library(DESeq2)
library(FactoMineR)
library(factoextra)
library(org.Hs.eg.db)
library(stringr)
library(stringi)
library(tidyverse)
library(ggplot2)
library(patchwork)
library(pheatmap)
library(VennDiagram)
library(RColorBrewer)

#读入数据
rawcount <- read.delim("counts.xls",header = T,sep="\t")  #读入制表符分隔的数据
rawcount <- rawcount[,1:10]   #保留1-10列
table(!duplicated(rawcount[,1]))   #table函数用来展示重复项的频数。duplicated函数用来表示是否重复数据,要不是重复的返回为FALSE。!duplicated是取duplicated的反相,原来是FALSE的,就变为TURE。
rownames(rawcount) <- rawcount[,1]  #设定行名
rawcount <- rawcount[,-1] #去掉第一列
#转换gene id
id2symbol <- bitr(rownames(rawcount),   
                  fromType = "ENSEMBL", 
                  toType = "SYMBOL", 
                  OrgDb = org.Hs.eg.db)
rawcount <- cbind(GeneID=rownames(rawcount),rawcount)  #cbind函数用来合并列
rawcount <- merge(id2symbol,rawcount,
                  by.x="ENSEMBL",by.y="GeneID",all.y=T) 
rawcount=rawcount[!duplicated(rawcount$SYMBOL),]  #去除重复symbol行
rawcount <- drop_na(rawcount)  #去除含有NA值的行
rawcount <- rawcount[,!colnames(rawcount)%in%c("ENSEMBL","Ensmble","median")]#正式获得基因rawcount矩阵
rownames(rawcount) <- rawcount[,1]
rawcount <- rawcount[,-1]
keep <- rowSums(rawcount>0) >= floor(0.5*ncol(rawcount)) #至少在50%的样本中都有表达的基因要保留下来
filter_count <- rawcount[keep,] #获得filter_count数据框
express_cpm<-log2(cpm(filter_count)+1)  #edgeR中的cpm函数将原始计数转换为CPM之后取log。得到的express_cpm是矩阵,而不是数据框。
save(express_cpm,filter_count,file="filterGeneCountCpm.Rdata")

说明
1,Y 叔的 clusterProfiler 包(v4.4.4)中有个函数 bitr() ,可以把Ensembl_ID 转 Symbol。原来的数据有58735行,生成id2symbol这个变量,只有35309行,也就是只有这么多基因找到了symbol名字。
2,用到cbind和merge这样的函数,可以对数据进行合并操作。cbind必须具有相同的行数,就可以把列合并了。R中的merge函数类似于Excel中的Vlookup,可以实现对两个数据表进行匹配和拼接的功能。by.x,by.y:用于制定进行合并的两个数据集的共同列,不必须行数相同。比如id2symbol的ENSEMBL行只有35309行,而rawcount的GeneID有58735行。all.y意思是y矩阵(即rawcount)的行应该全在输出文件里。因为y的行多于x的行,那么输出文件里就会有一些行里面有空的数据NA。
3,!a %in% b表示a不在b中为ture。也就是列名不是"ENSEMBL","Ensmble","median"这几个的都要保留。
4,rowSums(rawcount>0)获取count数大于0的样本个数。本例中有9个样本,所以每行rowSums后结果必定是0-9之间的整数。
5,cpm函数是edgeR中的一种基因定量方式,count-per-millon。原始的表达量除以该样本表达量的总和,在乘以一百万就得到了CPM值 。
6,express_cpm<-log2(cpm(filter_count)+1)这个命令里面,要用+1。因为log2(0)是无意义的,如果count里面有某个数是0,那么就没法计算了。所以这样正合适log2(1)=0,log2(2)=1, log2(4)=2....

二、WT和AI组两组间比较

#展示WT和AI组的整体表达情况
filter_count1 <- filter_count[,c(1,2,3,4,5,6)]
express_cpm1 <- express_cpm[,c(1,2,3,4,5,6)]
colnames(filter_count1) <- c("WT1","WT2",'WT3',"Ai1","Ai2",'Ai3') #给样本命名
colnames(express_cpm1) <- colnames(filter_count1)
group1=rep(c("WT","Ai"),each=3)
group_list1=factor(group1,levels = c("WT","Ai"))
table(group_list1) #检查一下组别数量
exprSet1 <- express_cpm1
data1 <- data.frame(expression=c(exprSet1),
                   sample=rep(colnames(exprSet1),each=nrow(exprSet1)))
p1.1 <- ggplot(data = data1,aes(x=sample,y=expression,fill=sample))
plot1.1 <- p1.1 + geom_boxplot() +xlab(NULL) + ylab("log2(CPM)")+theme_bw()+ 
         theme(panel.background = element_blank(), #去掉背景色
         panel.grid = element_blank(),   #去掉网格线
         axis.text.x = element_text(face="bold",angle = 45,hjust = 1,color = 'black'),
         axis.title.x = element_blank(),
         legend.direction = "vertical",
         legend.title =element_blank())
plot1.1 #展示出来plot

说明
1,用data.frame函数建立一个新的数据框,有两列分别为expression和sample。 expression是变量 exprSet1里的数据。对应sample列是把变量 exprSet1的列名标注出来,each变量为重复次数,即变量 exprSet1的行数。
2,ggplot画图,data参数指定绘图的数据,aes参数指定图的x轴,y轴是什么,fill是填充的颜色怎么区分。通常为fill=分组组名。
3,theme_bw() 类似默认背景,调整为白色背景和浅灰色网格线,无边框
4,theme参数里面有比较多的选项
axis.text.x = element_text(angle = 90)) 横坐标轴标签的方向
theme参数挺复杂的,但是可以使得图更美观
panel.grid = element_blank() # 网格线不要。如果想要这个参数就删掉。
panel.background = element_blank() #绘图区背景不要。其实有了theme_bw() 选项,这个background没啥用啊。
axis.title.x = element_blank() # x轴标题不要 ,如果要可以用element_text("xxx")来标注。
legend.title =element_blank() #图例标题不要,如果要可以用element_text("xxx")来标注。
这几个后面element_blank(),表示为空
5,xlab(NULL)表示x轴标签不显示。ylab("log2(CPM)")表示y轴标签为log2(CPM)

image.png
#WT和AI两组比较的PCA图
data1.2 <- data.frame(t(exprSet1)) #t()为转置,就是横竖对换
data1.2 <- na.omit(data1.2) #删除有NA的行
dat_pca1 <- PCA(data1.2[,], graph = FALSE)
plot1.2 <- fviz_pca_ind(dat_pca1,
                     geom.ind = "point", # 只显示点,不显示文字
                     mean.point=F, #去除中心的一个大点
                     col.ind = group_list1, # 用不同颜色表示分组
                     palette = c("#00AFBB", "#E7B800"),
                     addEllipses = T, # 是否圈起来,少于4个样圈不起来
                     legend.title = "Groups") + theme_bw()
plot1.2 #展示这个plot
ggsave(plot1.2, filename = "AIvsWT_PCA.jpg",width = 6,height = 4,units = "in",dpi = 300) 
image.png

说明
PCA函数是FactoMineR包里面的一个重要命令,用于分析。
fviz_pca_ind函数是R包factoextra里面的命令,用于作图。
上述两个R包相辅相成,一起完成主成分分析及作图。
mean.point=F这个选项如果不加,会为每个组自动添加一个大的中心点,不怎么好看。
palette选项是指定各个分组的颜色。如果有三组可以设成这样:palette = c("#00AFBB", "#E7B800", "#FC4E07"),#三个组设置三种颜色

#WT和AI两组表达的差异分析(用edgeR包做分析)
exprSet1 <- filter_count1
design1 <- model.matrix(~0+factor(group_list1))  #建立分组文件
rownames(design1) <- colnames(exprSet1) #行名
colnames(design1) <- levels(factor(group_list1))  #列名
DEG1 <- DGEList(counts=exprSet1,  
                group=factor(group_list1))
DEG1 <- calcNormFactors(DEG1)
# 计算线性模型的参数
DEG1 <- estimateGLMCommonDisp(DEG1,design1)
DEG1 <- estimateGLMTrendedDisp(DEG1, design1)
DEG1 <- estimateGLMTagwiseDisp(DEG1, design1)
# 拟合线性模型
fit1 <- glmFit(DEG1, design1)
lrt1 <- glmLRT(fit1, contrast=c(1,-1)) 
# 提取过滤差异分析结果
DEG_edgeR1 <- as.data.frame(topTags(lrt1, n=nrow(DEG1)))
head(DEG_edgeR1)
fc <- 2.0
p <- 0.05
DEG_edgeR1$regulated <- ifelse(DEG_edgeR1$logFC>log2(fc)&DEG_edgeR1$PValue<p,
                              "up",ifelse(DEG_edgeR1$logFC<(-log2(fc))&DEG_edgeR1$PValue<p,"down","normal"))
write.csv(DEG_edgeR1,"DEG1.csv")  

说明
DGEList函数是edgeR包中的用来构建一个含有组别标记的DGElist对象,是一个可以包含多种内容和统计的列表。用DGEList函数读取count matrix数据,需要提供一个现成的matrix数据,而不是指望它能读取单独的文件。前面已经有了exprSet1这个变量。用class()查看,它是matrix,可以直接调用。
counts 就是这个matrix,group是因子,即分组信息,一定要是factor才行。
前面命令是这样的:
group1=rep(c("WT","Ai"),each=3)
group_list1=factor(group1,levels = c("WT","Ai"))
class(group_list1)可以查看到它是“factor”,而class(group1)则是“character”
DGEList函数生成的对象DEG1有两个部分:counts(数据矩阵),sample(那些样本,分组情况),这个列表还可以添加更多内容,如下。
calcNormFactors这个函数,是计算每个样本的标准化参数,每个样本都用不同的参数,以消除由于测序深度以及有效文库大小不同等带来的影响。这一步之后每个样本norm.factors变得不同了。之前都是1。
estimateGLMCommonDisp(x,design):为所有基因都计算同样的dispersion。
estimateGLMTrendedDisp(x,design):根据不同基因的均值--方差之间的关系来计算dispersion,并拟合一个trended model。
estimateGLMTagwiseDisp(x,design):计算每个基因的dispersion,并利用经验性贝叶斯方法(empirical bayes)压缩至Trend Didspersion。
上面三个参数依此计算后,会在DGE1这个对象后面添加好几个参数,都是离散相关的系数之类。
之后,glmFit函数是根据design进行拟合,glmLRT函数利用likelihood ratio test(LRT)进行统计检验。glmFit 和 glmLRT 函数是配对使用的,用于 likelihood ratio test (似然比检验)。 contrast这个参数里面1和-1的前后位置无所谓。因为都是把WT作为对照组,AI作为实验组。在分组设定design1里面WT在前面就是对照。
之后生成数据框DEG_edgeR1

image.png

最后进行筛选。

#火山图
data1.3 <- DEG_edgeR1
plot1.3 <- ggplot(data=data1, aes(x=logFC, y=-log10(PValue),color=AIvsWT)) + 
  geom_point(alpha=0.5, size=1.8) + 
  theme_set(theme_set(theme_bw(base_size=20))) + 
  xlab("log2FC") + ylab("-log10(Pvalue)") +
  scale_colour_manual(values = c('blue','black','red'))+theme_bw()
plot1.3
ggsave(plot1.3, filename = "AIvsWT_volcano.jpg",width = 8,height = 6,units = "in",dpi = 300)
#热图
edgeR1_sigGene1 <- DEG_edgeR1[DEG_edgeR1$AIvsWT!="normal",]
edgeR1_sigGene1 <-rownames(edgeR1_sigGene1)
data1.4 <- express_cpm1[match(edgeR1_sigGene1,rownames(express_cpm1)),]
data1.4[1:4,1:4]
group1 <- data.frame(group=group_list1)
rownames(group1)=colnames(data1.4)
library(pheatmap)
plot1.4 <- pheatmap(data1.4,scale = "row",show_colnames =T,show_rownames = F, 
                 cluster_cols = T, 
                 annotation_col=group1,
                 main = "edgeR's DEG")
library(ggplotify)
plot1.4 <- as.ggplot(plot1.4)
plot1.4
ggsave(plot1.4,filename = "AIvsWT_heatmap.jpg",width = 8,height = 6,units = "in",dpi = 300 )

用ggsave命令把前面做出来的图保存在工作目录下。

三、Y19FvsWT两组间比较

#Y19FvsWT 
#  boxplot
filter_count2 <- filter_count[,c(1,2,3,7,8,9)]
express_cpm2 <- express_cpm[,c(1,2,3,7,8,9)]
colnames(filter_count2) <- c("WT1","WT2",'WT3',"Y19F1","Y19F2","Y19F3")
colnames(express_cpm2) <- colnames(filter_count2)
group2=rep(c("WT","Y19F"),each=3)
group_list2=factor(group2,levels = c("WT","Y19F"))
exprSet2 <- express_cpm2
data2.1 <- data.frame(expression=c(exprSet2),
                      sample=rep(colnames(exprSet2),each=nrow(exprSet2)))
p2.1 <- ggplot(data = data2.1,aes(x=sample,y=expression,fill=sample))
plot2.1 <- p2.1 + geom_boxplot(outlier.shape = NA) +xlab("sample") + ylab("log2(CPM)")+theme_bw()+ 
  theme(panel.background = element_blank(),
        panel.grid = element_blank(),  
        axis.text.x = element_text(face="bold",angle = 45,hjust = 1,color = 'black'),
        axis.title.x = element_blank(),
        legend.direction = "vertical",
        legend.title =element_blank())
plot2.1
ggsave(plot2.1, filename = "AIvsY19F_boxplot.jpg",width = 6,height = 4,units = "in",dpi = 300)
#AI$WT PCA
data2.2 <- data.frame(t(exprSet2))
data2.2 <- na.omit(data2.2)
dat_pca2 <- PCA(data2.2[,], graph = FALSE)
plot2.2 <- fviz_pca_ind(dat_pca1,
                        geom.ind = "point", 
                        mean.point=F,
                        col.ind = group_list1, 
                        palette = c("#00AFBB", "#E7B800"),
                        addEllipses = T, 
                        legend.title = "Groups") + theme_bw()
plot2.2
ggsave(plot2.2, filename = "AIvsY19F_PCA.jpg",width = 6,height = 4,units = "in",dpi = 300)
# DEG using edgeR
exprSet2 <- filter_count2
design2 <- model.matrix(~0+factor(group_list2))
rownames(design2) <- colnames(exprSet2)
colnames(design2) <- levels(factor(group_list2))
DEG2 <- DGEList(counts=exprSet2,  
                group=factor(group_list2))
DEG2 <- calcNormFactors(DEG2)
DEG2 <- estimateGLMCommonDisp(DEG2,design2)
DEG2 <- estimateGLMTrendedDisp(DEG2, design2)
DEG2 <- estimateGLMTagwiseDisp(DEG2, design2)
fit2 <- glmFit(DEG2, design1try)
lrt2 <- glmLRT(fit2, contrast=c(-1,1)) 
DEG_edgeR2<- as.data.frame(topTags(lrt2, n=nrow(DEG2)))
fc <- 2.0
p <- 0.05
DEG_edgeR2$AIvsY19F <- ifelse(DEG_edgeR2$logFC>log2(fc)&DEG_edgeR2$PValue<p,
                              "up",ifelse(DEG_edgeR2$logFC<(-log2(fc))&DEG_edgeR2$PValue<p,"down","normal"))
table(DEG_edgeR2$AIvsWT)

write.csv(DEG_edgeR1,"DEG2.csv")

#volcano
data2.3 <- DEG_edgeR2
plot2.3 <- ggplot(data=data2.3, aes(x=logFC, y=-log10(PValue),color=AIvsY19F)) + 
  geom_point(alpha=0.5, size=1.8) + 
  theme_set(theme_set(theme_bw(base_size=20))) + 
  xlab("log2FC") + ylab("-log10(Pvalue)") +
  scale_colour_manual(values = c('blue','black','red'))+theme_bw()
plot2.3
ggsave(plot2.3, filename = "AIvsY10F_volcano.jpg",width = 8,height = 6,units = "in",dpi = 300)
#heatmap
edgeR2_sigGene2 <- DEG_edgeR2[DEG_edgeR2$AIvsY19F!="normal",]
edgeR2_sigGene2 <-rownames(edgeR2_sigGene2)
data2.4 <- express_cpm2[match(edgeR2_sigGene2,rownames(express_cpm2)),]
data2.4[1:4,1:4]
group2 <- data.frame(group=group_list2)
rownames(group2)=colnames(data2.4)
library(pheatmap)
plot2.4 <- pheatmap(data2.4,scale = "row",show_colnames =T,show_rownames = F, 
                    cluster_cols = T, 
                    annotation_col=group2,
                    main = "edgeR's DEG")
library(ggplotify)
plot2.4 <- as.ggplot(plot2.4)
plot2.4
ggsave(plot2.4,filename = "AIvsY19F_heatmap.jpg",width = 8,height = 6,units = "in",dpi = 300 )

四、三个样本,在两两比较后的整合韦恩图

# 整体venn图,包含上调下调的
deg1 <- rownames(DEG_edgeR1[DEG_edgeR1$AIvsWT!="normal",])
up1 <- rownames(DEG_edgeR1[DEG_edgeR1$AIvsWT=="up",])
down1 <- rownames(DEG_edgeR1[DEG_edgeR1$AIvsWT=="down",])
deg2 <- rownames(DEG_edgeR2[DEG_edgeR2$Y19FvsWT!="normal",])
up2 <- rownames(DEG_edgeR2[DEG_edgeR2$Y19FvsWT=="up",])
down2 <- rownames(DEG_edgeR2[DEG_edgeR2$Y19FvsWT=="down",])
library(ggvenn)
deg<-list(`AIvsWT`=deg1,
          `Y19FvsWT`=deg2)
plot5 <- ggvenn(deg,
             show_percentage = F,
             stroke_color = "white",
             fill_color = c("#b2d4ec","#d3c0e2"),
             set_name_color = c("#ff0000","#4a9b83"))
plot5
plot5 <- as.ggplot(plot5)
ggsave(plot5, filename = "venn.jpg",width = 6,height = 4,units = "in",dpi = 300)
#上调,下调的韦恩图
up<-list(`up1`=up1,
         `up2`=up2)

plot6 <- ggvenn(up,
             show_percentage = F,
             stroke_color = "white",
             fill_color = c("#ffb2b2","#b2e7cb"),
             set_name_color = c("#ff0000","#4a9b83"))
plot6
plot6 <- as.ggplot(plot6)
ggsave(plot6, filename = "venn-up.jpg",width = 6,height = 4,units = "in",dpi = 300)
down<-list(`down1`=down1,
           `down2`=down2)

plot7 <- ggvenn(down,
             show_percentage = F,
             stroke_color = "white",
             fill_color = c("#b2d4ec","08a4ad"),
             set_name_color = c("#ff0000","#4a9b83"))
plot7
plot7 <- as.ggplot(plot7)
ggsave(plot7, filename = "venn-down.jpg",width = 6,height = 4,units = "in",dpi = 300)

说明
ggvenn是基于ggplot2的专门绘制韦恩图的R包。韦恩图,Venn diagram是用来展示集合的共性和特性。
先分别读取各个集合,比如第一组和第二组比较的差异基因集合deg1和deg2,以及上调基因集合up1/up2,下调基因集合down1/down2。每个集合都是一个列表,其中包含基因名。
[DEG_edgeR1$AIvsWT!="normal",]是取AIvsWT这一列为非normal的行。再把这些行的行名赋值给deg1这个变量。
在用list把需要做图的集合(可以是两个,三个或更多)赋值给一个对象。这里可以对每个集合进行命名,之后在图中就会显示该集合的名字。
最后用ggvenn函数为这个对象做图。

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

推荐阅读更多精彩内容