引入

平常我们利用GEODatasets的表达量数据进行基因表达分析的时候,常常是下载表达矩阵,利用limma包进行分析,如果能找到注释包,那就把探针注释成Entrez_id或者是Symbol_id,如果找不到,那就下载对应GPL提供的注释文件,但是很可能还是不好注释,比如今天拿来做例子的GSE15222对应的GPL2700:
我们看到这个GPL只提供了GB_ACC也就是Genebank的一个号码,我们还要先将其转换成Entrez_id或者是Symbol_id(这个过程如果找不到好的工具很难完美地完成),然后利用Python或者Excel把这个GPL注释文件和下载的表达矩阵联系起来······如果你尝试着做一遍的话会发现非常消耗时间和精力。
但是,如果我们注意到GEO2R的话,会发现这个Series通过GEO Gatabase的在线分析工具GEO2R的分析之后,提供的结果是这个样子:
结果中竟然直接给了symbol_id!那么我们怎么才能得到这个呢?

GEO2R的运行脚本

GEO2R提供了分析的R脚本。

# Version info: R 3.2.3, Biobase 2.30.0, GEOquery 2.40.0, limma 3.26.8
# R scripts generated  Tue Jan 15 02:03:41 EST 2019################################################################
#   Differential expression analysis with limma
library(Biobase)
library(GEOquery)
library(limma)# load series and platform data from GEOgset <- getGEO("GSE15222", GSEMatrix =TRUE, AnnotGPL=TRUE)
if (length(gset) > 1) idx <- grep("GPL2700", attr(gset, "names")) else idx <- 1
gset <- gset[[idx]]# make proper column names to match toptable
fvarLabels(gset) <- make.names(fvarLabels(gset))# group names for all samples
gsms <- paste0("XX000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX111","1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXX")
sml <- c()
for (i in 1:nchar(gsms)) { sml[i] <- substr(gsms,i,i) }# eliminate samples marked as "X"
sel <- which(sml != "X")
sml <- sml[sel]
gset <- gset[ ,sel]# log2 transform
ex <- exprs(gset)
qx <- as.numeric(quantile(ex, c(0., 0.25, 0.5, 0.75, 0.99, 1.0), na.rm=T))
LogC <- (qx[5] > 100) ||(qx[6]-qx[1] > 50 && qx[2] > 0) ||(qx[2] > 0 && qx[2] < 1 && qx[4] > 1 && qx[4] < 2)
if (LogC) { ex[which(ex <= 0)] <- NaNexprs(gset) <- log2(ex) }# set up the data and proceed with analysis
sml <- paste("G", sml, sep="")    # set group names
fl <- as.factor(sml)
gset$description <- fl
design <- model.matrix(~ description + 0, gset)
colnames(design) <- levels(fl)
fit <- lmFit(gset, design)
cont.matrix <- makeContrasts(G1-G0, levels=design)
fit2 <- contrasts.fit(fit, cont.matrix)
fit2 <- eBayes(fit2, 0.01)
tT <- topTable(fit2, adjust="fdr", sort.by="B", number=250)tT <- subset(tT, select=c("ID","adj.P.Val","P.Value","t","B","logFC","Gene.symbol","Gene.title"))
write.table(tT, file=stdout(), row.names=F, sep="\t")################################################################
#   Boxplot for selected GEO samples
library(Biobase)
library(GEOquery)# load series and platform data from GEOgset <- getGEO("GSE15222", GSEMatrix =TRUE, getGPL=FALSE)
if (length(gset) > 1) idx <- grep("GPL2700", attr(gset, "names")) else idx <- 1
gset <- gset[[idx]]# group names for all samples in a series
gsms <- paste0("XX000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX111","1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","XXXXXXXXXXXXX")
sml <- c()
for (i in 1:nchar(gsms)) { sml[i] <- substr(gsms,i,i) }
sml <- paste("G", sml, sep="")  set group names# eliminate samples marked as "X"
sel <- which(sml != "X")
sml <- sml[sel]
gset <- gset[ ,sel]# order samples by group
ex <- exprs(gset)[ , order(sml)]
sml <- sml[order(sml)]
fl <- as.factor(sml)
labels <- c("1","2")# set parameters and draw the plot
palette(c("#dfeaf4","#f4dfdf", "#AABBCC"))
dev.new(width=4+dim(gset)[[2]]/5, height=6)
par(mar=c(2+round(max(nchar(sampleNames(gset)))/2),4,2,1))
title <- paste ("GSE15222", '/', annotation(gset), " selected samples", sep ='')
boxplot(ex, boxwex=0.6, notch=T, main=title, outline=FALSE, las=2, col=fl)
legend("topleft", labels, fill=palette(), bty="n")

分析这个R脚本我们能学到很多东西。首先,就是它的数据从哪里来?

在线获取表达矩阵

很明显,gset <- getGEO("GSE15222", GSEMatrix =TRUE, AnnotGPL=TRUE),这一句就直接获得了表达矩阵。我们按照bioconductor的方法安装好Biobase、GEOquery、limma三个包,运行这一句,得到gset是一个很复杂的列表:
这个列表就是一个非常关键的数据。它不仅包括了我们可以下载的探针及其对应的表达量,还包括了Entrez_id和Symbol_id!
我们可以使用gset$GSE15222_series_matrix.txt.gz@featureData[[1]]显示探针数据
gset$GSE15222_series_matrix.txt.gz@featureData[[2]]显示基因的功能
gset$GSE15222_series_matrix.txt.gz@featureData[[3]]显示symbol_id
gset$GSE15222_series_matrix.txt.gz@featureData[[4]]显示entrez_id

使用expr<-exprs(gset[[1]])获得我们需要的表达矩阵,它现在是这个样子:
探针名现在是列名。

合并对应基因相同的探针

我们知道有一些探针并不对应基因,还有很多探针可能对应同一个基因。这要求我们合并对应基因相同的探针,删除不对应基因的探针
在合并之前,先说一句Entrez_id和Symbol_id的关系。根据我的查询,Entrez_id对应Symbol_id是一个单射,一个Symbol_id可能对应多个Entrez_id。因此Entrez_id更为具体,我们合并探针直接将其转化为Entrez_id进行合并。那么这个时候为什么不直接在表达矩阵里注释上Symbol_id呢?这还要从合并方式谈起。
合并探针,我们使用的是函数aggregate(),有关于该函数的更多内容可以从R Studio内查询。
首先我们将entrez id直接作为一列插入到第一列前面(这也体现这种方法的方便性,对应关系已经给你弄好了):

entrez<-gset$GSE15222_series_matrix.txt.gz@featureData[[4]]
expr<-cbind(entrez,expr)
entrez=expr[,1]

现在expr是这个样子:


然后运行我们的合并并删除赘余的函数(调整参数可以选择合并方式,我这里选择的是根据entrez这个list进行合并,表达量合并时取平均值):

mydf<-aggregate(expr, by=list(entrez), FUN=mean)

合并之后我们获得的mydf是这样的(由于这个系列样本较多,因此运行时间较长,需要等几分钟):

现在,这个数据框是按照entrez这列排的序,前面呢,多了一个Group.1这一列。我们接下来的任务是把entrez id放到列名,并且删去多余的这两列

mydf <- subset(mydf, select = -entrez)
row.names(mydf)<-mydf$Group.1
mydf <- subset(mydf, select = -Group.1)

表达矩阵变成了这个样子:

这时反过来想想为什么不能在之前加入Symbol_id。之前加入Symbol_id是很简单,直接插入这一列就好了。但是aggregate()函数并不能处理字符串,会把他们当成NA,所以加入Symbol_id相当于白加了。那么现在加Symbol_id可以吗?还是不行。因为接下来我们进行差异表达分析的时候仍然不能出现非数字类型的数据。

进行差异表达分析

这一步应该不用讲太多,算是很基础的一步了。
首先生成设计矩阵:

type <-c('Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD')
design <- model.matrix(~ -1+factor(type,levels=c('Control','AD'),ordered=TRUE))
colnames(design) <- c('Control','AD')
rownames(design)=colnames(mydf)

然后借助limma包进行差异表达分析就好了:

fit=lmFit(mydf, design)contrast.matrix=makeContrasts(ControlVSAD=Control-AD,levels=design)
fit2 = contrasts.fit(fit, contrast.matrix)
fit2 = eBayes(fit2)
results <- decideTests(fit2)
vennDiagram(results)
#vennDiagram(object, include="both", names, mar=rep(1,4), cex=1.5, lwd=1, circle.col, counts.col, show.include, ...)diff1 = topTreat(fit2, coef=1,p.value=0.05, n=Inf, adjust.method='BH')

此时的diff1是这个样子,按照调整后的P值排序的表,行名是Entrez_id:

添加Symbol_id

终于可以添加Symbol_id了。但是我们知道这个数据已经被打乱了,不仅探针合并、删除,最后的结果还是按照调整后的P值排序的。怎么让Symbol_id在diff1中对应上呢?那就要动用apply()函数了。
刚开始读入数据之后,我们首先创建一个id之间的对应字典

symbol_id<-gset$GSE15222_series_matrix.txt.gz@featureData[[3]]
entrez<-gset$GSE15222_series_matrix.txt.gz@featureData[[4]]
id<-cbind(entrez,symbol_id)

id是这样子的一个表:

获得diff1后,我们将diff1的行名,也就是Entrez_id提取出来作为一个数据框(列表),这样我们就获得了Entrez_id的顺序

rn<-vector()
for(i in row.names(diff1)) rn<-c(rn,i)
rn<-as.data.frame(rn)

rn就是列名,接下来使用apply()函数,将id中的symbol_identrez作为字典中的"key"对应rn

SYMBOL <-apply(rn,1,  # 1 by row, 2 by columnfunction(x) id[which(id[,1]==x[1]),2][1] #如果最后不取[1](第一个元素),能合并的不同探针对应多个相同的entrez会重复出现在SYMBOL的一个位置
)

获得SYMBOL

然后把它加到diff1的第一列即可:

diff1<-cbind(SYMBOL,diff1)

diff1就是最终我们需要的矩阵(如果需要基因信息也可以将基因信息加入),也可以将其导出为TXT:

源代码

最后贴上分析GSE15222的所有代码:

#   Differential expression analysis with limma
library(Biobase)
library(GEOquery)
library(limma)# load series and platform data from GEOgset <- getGEO("GSE15222", GSEMatrix =TRUE, AnnotGPL=TRUE)
expr<-exprs(gset[[1]])
probe<-gset$GSE15222_series_matrix.txt.gz@featureData[[1]]
symbol_id<-gset$GSE15222_series_matrix.txt.gz@featureData[[3]]
entrez<-gset$GSE15222_series_matrix.txt.gz@featureData[[4]]
expr<-cbind(entrez,expr)id<-cbind(entrez,symbol_id)entrez=expr[,1]mydf<-aggregate(expr, by=list(entrez), FUN=mean)
mydf <- subset(mydf, select = -entrez)
row.names(mydf)<-mydf$Group.1
mydf <- subset(mydf, select = -Group.1)type <-c('Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','Control','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD','AD')
design <- model.matrix(~ -1+factor(type,levels=c('Control','AD'),ordered=TRUE))
colnames(design) <- c('Control','AD')
rownames(design)=colnames(mydf)fit=lmFit(mydf, design)contrast.matrix=makeContrasts(ControlVSAD=Control-AD,levels=design)
fit2 = contrasts.fit(fit, contrast.matrix)
fit2 = eBayes(fit2)
results <- decideTests(fit2)
vennDiagram(results)
#vennDiagram(object, include="both", names, mar=rep(1,4), cex=1.5, lwd=1, circle.col, counts.col, show.include, ...)diff1 = topTreat(fit2, coef=1,p.value=0.05, n=Inf, adjust.method='BH')rn<-vector()
for(i in row.names(diff1)) rn<-c(rn,i)
rn<-as.data.frame(rn)
SYMBOL <-apply(rn,1,  # 1 by row, 2 by columnfunction(x) id[which(id[,1]==x[1]),2][1]
)
diff1<-cbind(SYMBOL,diff1)write.table(diff1, "diff.ControlVSAD.GSE15222.txt",sep = '\t',quote = F)

R语言 使用getGEO()直接进行差异表达分析并显示Entrez_id和Symbol_id相关推荐

  1. 使用R语言ggplot2包绘制pathway富集分析气泡图(Bubble图):数据结构及代码

    气泡图是在笛卡尔坐标系同加入大小的参数所形成的可以表示三个变量关系的图例.在对基因完成GO/KEGG分析后,使用气泡图可以直观的展示pathway.pvalue.count之间的关系.下面为使用R语言 ...

  2. 使用R语言绘制富集条形图,轻松分析基因表达数据

    一.引言 富集分析(enrichment analysis)是一种生物信息学方法,它可以帮助我们识别基因或其他的生物实体在某个特定的类别中过度表示的趋势.通俗来说,富集分析通过将基因分类到特定的集合中 ...

  3. R语言使用Rtsne包进行TSNE分析:通过数据类型筛选数值数据、scale函数进行数据标准化缩放、提取TSNE分析结果合并到原dataframe中(tSNE with Rtsne package)

    R语言使用Rtsne包进行TSNE分析:通过数据类型筛选数值数据.scale函数进行数据标准化缩放.提取TSNE分析结果合并到原dataframe中(tSNE with Rtsne package) ...

  4. R语言使用Rtsne包进行TSNE分析:提取TSNE分析结果合并到原dataframe中、可视化tsne降维的结果、并圈定降维后不匹配的数据簇(tSNE identifying mismatch)

    R语言使用Rtsne包进行TSNE分析:提取TSNE分析结果合并到原dataframe中.可视化tsne降维的结果.并使用两个分类变量从颜色.形状两个角度来可视化tsne降维的效果.并圈定降维后不匹配 ...

  5. R语言诊断试验数据处理与ROC分析实战案例2

    R语言诊断试验数据处理与ROC分析实战案例2 目录 R语言诊断试验数据处理与ROC分析实战案例2 #ROC指标 #样例数据

  6. R语言诊断试验数据处理与ROC分析实战案例1

    R语言诊断试验数据处理与ROC分析实战案例1 目录 R语言诊断试验数据处理与ROC分析实战案例1 #ROC指标 #样例数据

  7. R语言诊断试验数据处理与ROC分析实战案例:联合诊断ROC

    R语言诊断试验数据处理与ROC分析实战案例:联合诊断ROC 目录 R语言诊断试验数据处理与ROC分析实战案例:联合诊断ROC #ROC指标 #样例数据

  8. R语言时间序列(time series)分析实战:简单指数平滑法预测

    R语言时间序列(time series)分析实战:简单指数平滑法预测 目录

  9. R语言时间序列(time series)分析实战:HoltWinters平滑法预测

    R语言时间序列(time series)分析实战:HoltWinters平滑法预测 目录

  10. R语言时间序列(time series)分析实战:霍尔特指数Holt‘s平滑法预测

    R语言时间序列(time series)分析实战:霍尔特指数Holt's平滑法预测 目录

最新文章

  1. 宇宙射线会导致路由器 bug,思科你认真的吗
  2. UNITY 复制对象后局部坐标和世界坐标的变化问题
  3. c++享元模式flyweight
  4. 优化混合云性能:数据管理技巧大公开
  5. Windows 2008活动目录的安装和卸载
  6. 张庆余(1991-),男,北京卡达克数据技术中心软件业务本部助理工程师,主要研究方向为软件架构、云计算。...
  7. Spring Boot+Ext JS准前后端框架应用的会话(Session)处理
  8. oracle视图用法,oracle视图大全
  9. 基于深度神经网络的大规模植物分类
  10. ANE 在 Android 上的应用
  11. 传统JDBC的弊病和mybatis的解决方案
  12. 美国西海岸php,美国西海岸大学top 14
  13. 搜索场 day1 A 求和
  14. 运用集合把文字写入读出文件
  15. 工程力学和计算机专业,工程力学本科专业介绍
  16. python开发网页视频播放器_python实现媒体播放器功能
  17. hutool导出导出excel中文自适应列宽+反射+自定义注解获取表头
  18. [分享]来自CSDN的精华网址
  19. js 输出为underfined
  20. SAP 公司间标准委外流程

热门文章

  1. php中超链接怎么去下划线的,html如何去掉超链接下划线?html超链接去掉下划线的方法介绍...
  2. Android 图片剪切框架 uCrop 简单集成
  3. 移动网络安装测试软件,家宽众测中国移动手机版(在线宽带网速测试器)V2.0.3 去广告版...
  4. 关于逻辑关系 “隐含(implies、p-q) 的理解
  5. 各种串口助手工具分享
  6. Activity及其生命周期
  7. 如何提取mp4中的音频?
  8. 电子地图有比例尺吗?
  9. 时间序列分析 | 相似性度量基本方法
  10. 用自动控制理论分析电力电子中的基本斩波电路