12

R包精讲第三篇:如何切换镜像?

这个技巧很重要,一般来说,R语言自带的install.packages函数来安装一个包时,都是用的默认的镜像!

如果你是用的Rstudio这个IDE,你的默认镜像就是: https://cran.rstudio.com/

如果你直接用的R语言,那么就是:"http://cran.us.r-project.org" 但是一般你安装的时候会提醒你选择。

Continue reading

12

R包精讲第二篇:如何安装旧版本的包?

既然你点进来看,肯定是有需求咯!
一般来说,R语言自带的install.packages函数来安装一个包时,都是默认安装最新版的。
但是有些R包的开发者他会引用其它的一些R包,但是它用的是人家旧版本的功能,但他自己来不及更新或者疏忽了。
而我们又不得不用他的包,这时候就不得不卸载最新版包,转而安装旧版本包。

Continue reading

11

R包精讲第一篇:如何查看你已经安装了和可以安装哪些R包?

最近经常出现一个错误,类似于package ‘airway’ is not available (for R version 3.1.0)

就是某些包在R的仓库里面找不到,这个错误非常普遍,stackoverflow上面非常详细的解答:

http://stackoverflow.com/questions/25721884/how-should-i-deal-with-package-xxx-is-not-available-for-r-version-x-y-z-wa

在阅读这个答案的时候,我发现了一个非常有用的函数!available.packages()可以查看自己的机器可以安装哪些包!

Continue reading

23

强烈推荐用shiny来制作交互式网页展现数据

shiny是Rstudio公司推出的一个网页服务器,可以直接用R语言制作客户端和服务端程序来交互式的展现数据,而且有越来越丰富的扩展包可以借鉴使用,我觉得它的前途很光明,值得大家入坑!

虽然Rstudio公司吹嘘初学者无需具备html和css,js基础,但是个人认为还是多了解一下比较好,可以在w3cschool里面在线学习!

新手安装好shiny包之后里面自带了12个app例子,一边调试一边学习,很快就可以入门了。推荐一个教程,用shiny构建网页中文教程,想查看更详细的介绍和实例,请访问Shiny的官方主页。当然,你肯定需要要会R,这里有个R的FAQ教程。

如果你完全看完了上面那些,说明你已经真正入门了!

你现在可以去搜索一个shiny cheetsheet,然后背诵下来!!!!

然后你可以去shiny的github里面找到108个示例程序,一个个运行了解它们!!!

这时候你已经是高手啦!!!

接下来你应该取了解一个叫做dashboard的东西,熟练UI界面设计。

最后你再了解一些辅助包,帮助你用shiny更好的展示数据,主要是JS绘图插件

里面最出名的就是DT包了,一定要学!!!

最后你可以了解一下在rstudio上面分享五个免费的shiny网页程序,需要你搜索一些。

如果你还感兴趣的话,就可以自己整一个虚拟机Ubuntu或者centos系统,试着安装shiny的server,这个比较考验技术。

总结:你可以需要200个小时左右来完全掌握shiny

03

用R语言包从EBI的arrayexpress数据库里面下载芯片数据

这个包跟GEOquery区别不是很大,只不过一个是正对NCBI的GEO数据库,一个是针对EBI的arrayexpress数据库,只有对写自动化脚本的人来说才有需求,一般个人分析者都是自己去数据库主页里面查找,然后拿到下载链接,一个个下载。
从EBI的arrayexpress数据库里面下载芯片数据:
update to 2016-3-1 11:41:27
63890 experiments
1912744 assays
40.53 TB of archived data 数据量还是蛮大的
所有的data,都可以在ftp服务器里面下载:ftp://ftp.ebi.ac.uk/pub/databases/arrayexpress/data/experiment/BUGS/
根据ID号很整齐的储存着。
也可以用一个R语言包:ArrayExpress R package
2009年,那个时候R语言用的人很少,这个简单的包都可以发文章,现在看来简直不可思议!
其实大部分数据都是跟GEO数据库对应的:比如https://www.ebi.ac.uk/arrayexpress/experiments/E-GEOD-55645/  对应于:GEO - GSE55645
比如对NASH表达数据查找:https://www.ebi.ac.uk/arrayexpress/search.html?query=NASH++expression  30条结果里面只有4条是arrayexpress数据库独有的!
biocLite("ArrayExpress")
library(ArrayExpress)
1
如果用R语言,搜索如下:
可以用sets = queryAE(keywords = "NASH+expression", species = "homo+sapiens")
2
效果是一样的!
下载数据用:
back = getAE("E-MEXP-3291")
下载其实也就是里面存储了链接,直接调用R语言的下载函数即可!
3
一般没必要下载原始测序文件,直接用下面这个函数就可以得到一个数据对象,可以直接得到表达矩阵和实验的metadata

rawset = ArrayExpress("E-MEXP-3291")

28

用R的shiny包写一个基因的ID转换小程序

基因的ID现在可能有一千多种,但是我们一般只用NCBI的entrez ID,和HUGO组装规定的gene symbol和gene name
再者有人会用ensembl的ID,至于UCSC的ID很少人用了,更别说剩余的一大堆稀奇古怪的ID了。
ID_example
其实没必要自己写一个软件来转换,因为非常多的现成软件都可以做到!
不过可以拿这个简单的任务来练手!
首先自己做好数据库文件:
我是把数据写到了一个sqlite文件里面了!结构很简单
然后设计软件的界面,俗称UI端,也是很容易,在shiny里面,记住几个控件的函数即可!
UI_1 UI_2
具体代码见我的github代码:https://github.com/jmzeng1314/my-R/tree/master/4-ID-convert-using-shiny
15

用R获取芯片探针与基因的对应关系三部曲-bioconductor

现有的基因芯片种类不要太多了!

但是重要而且常用的芯片并不多!
一般分析芯片数据都需要把探针的ID切换成基因的ID,我一般喜欢用基因的entrez ID。
一般有三种方法可以得到芯片探针与gene的对应关系。
金标准当然是去基因芯片的厂商的官网直接去下载啦!!!
一种是直接用bioconductor的包

一种是从NCBI里面下载文件来解析好!
首先,我们说官网,肯定可以找到,不然这种芯片出来就没有意义了!
然后,我们看看NCBI下载的,会比较大
这两种方法都比较麻烦,需要一个个的来!
所以我接下来要讲的是用R的bioconductor包来批量得到芯片探针与gene的对应关系!
一般重要的芯片在R的bioconductor里面都是有包的,用一个R包可以批量获取有注释信息的芯片平台,我选取了常见的物种,如下:
        gpl           organism                  bioc_package
1     GPL32       Mus musculus                        mgu74a
2     GPL33       Mus musculus                        mgu74b
3     GPL34       Mus musculus                        mgu74c
6     GPL74       Homo sapiens                        hcg110
7     GPL75       Mus musculus                     mu11ksuba
8     GPL76       Mus musculus                     mu11ksubb
9     GPL77       Mus musculus                     mu19ksuba
10    GPL78       Mus musculus                     mu19ksubb
11    GPL79       Mus musculus                     mu19ksubc
12    GPL80       Homo sapiens                        hu6800
13    GPL81       Mus musculus                      mgu74av2
14    GPL82       Mus musculus                      mgu74bv2
15    GPL83       Mus musculus                      mgu74cv2
16    GPL85  Rattus norvegicus                        rgu34a
17    GPL86  Rattus norvegicus                        rgu34b
18    GPL87  Rattus norvegicus                        rgu34c
19    GPL88  Rattus norvegicus                         rnu34
20    GPL89  Rattus norvegicus                         rtu34
22    GPL91       Homo sapiens                      hgu95av2
23    GPL92       Homo sapiens                        hgu95b
24    GPL93       Homo sapiens                        hgu95c
25    GPL94       Homo sapiens                        hgu95d
26    GPL95       Homo sapiens                        hgu95e
27    GPL96       Homo sapiens                       hgu133a
28    GPL97       Homo sapiens                       hgu133b
29    GPL98       Homo sapiens                     hu35ksuba
30    GPL99       Homo sapiens                     hu35ksubb
31   GPL100       Homo sapiens                     hu35ksubc
32   GPL101       Homo sapiens                     hu35ksubd
36   GPL201       Homo sapiens                       hgfocus
37   GPL339       Mus musculus                       moe430a
38   GPL340       Mus musculus                     mouse4302
39   GPL341  Rattus norvegicus                       rae230a
40   GPL342  Rattus norvegicus                       rae230b
41   GPL570       Homo sapiens                   hgu133plus2
42   GPL571       Homo sapiens                      hgu133a2
43   GPL886       Homo sapiens                     hgug4111a
44   GPL887       Homo sapiens                     hgug4110b
45  GPL1261       Mus musculus                    mouse430a2
49  GPL1352       Homo sapiens                       u133x3p
50  GPL1355  Rattus norvegicus                       rat2302
51  GPL1708       Homo sapiens                     hgug4112a
54  GPL2891       Homo sapiens                       h20kcod
55  GPL2898  Rattus norvegicus                     adme16cod
60  GPL3921       Homo sapiens                     hthgu133a
63  GPL4191       Homo sapiens                       h10kcod
64  GPL5689       Homo sapiens                     hgug4100a
65  GPL6097       Homo sapiens               illuminaHumanv1
66  GPL6102       Homo sapiens               illuminaHumanv2
67  GPL6244       Homo sapiens   hugene10sttranscriptcluster
68  GPL6947       Homo sapiens               illuminaHumanv3
69  GPL8300       Homo sapiens                      hgu95av2
70  GPL8490       Homo sapiens   IlluminaHumanMethylation27k
71 GPL10558       Homo sapiens               illuminaHumanv4
72 GPL11532       Homo sapiens   hugene11sttranscriptcluster
73 GPL13497       Homo sapiens         HsAgilentDesign026652
74 GPL13534       Homo sapiens  IlluminaHumanMethylation450k
75 GPL13667       Homo sapiens                        hgu219
76 GPL15380       Homo sapiens      GGHumanMethCancerPanelv1
77 GPL15396       Homo sapiens                     hthgu133b
78 GPL17897       Homo sapiens                     hthgu133a
这些包首先需要都下载
gpl_info=read.csv("GPL_info.csv",stringsAsFactors = F)
### first download all of the annotation packages from bioconductor
for (i in 1:nrow(gpl_info)){
  print(i)
  platform=gpl_info[i,4]
  platform=gsub('^ ',"",platform) ##主要是因为我处理包的字符串前面有空格
  #platformDB='hgu95av2.db'
  platformDB=paste(platform,".db",sep="")
  if( platformDB  %in% rownames(installed.packages()) == FALSE) {
    BiocInstaller::biocLite(platformDB)
    #biocLite(platformDB )
  }
}
下载完了所有的包, 就可以进行批量导出芯片探针与gene的对应关系!
for (i in 1:nrow(gpl_info)){
  print(i)
  platform=gpl_info[i,4]
  platform=gsub('^ ',"",platform)
  #platformDB='hgu95av2.db'
  platformDB=paste(platform,".db",sep="")
  if( platformDB  %in% rownames(installed.packages()) != FALSE) {
    library(platformDB,character.only = T)
    #tmp=paste('head(mappedkeys(',platform,'ENTREZID))',sep='')
    #eval(parse(text = tmp))
###重点在这里,把字符串当做命令运行
    all_probe=eval(parse(text = paste('mappedkeys(',platform,'ENTREZID)',sep='')))
    EGID <- as.numeric(lookUp(all_probe, platformDB, "ENTREZID"))
##自己把内容写出来即可
  }
}

 

 

31

画基因的外显子覆盖度图

一般情况下,我们得到了测序reads在基因组的比对情况文件bam格式的,里面的信息非常多,如果我想特定的查看某个基因的情况,那么我们可以选择IGV等可视化工具,但它并不是万能的,因为即使是一个基因,它也会有多个转录本,多个外显子。
所以,我们可以画它的外显子覆盖图,如下:横坐标是外显子的长度,纵坐标是测序深度,每一个小图都是一个外显子
 DMD.NM_000109
根据这个图,我们就可以很明显的看出,DMD基因NM_000109转录本的1,10-17号外显子缺失,用IGV一个个的看这些外显子区域,是同样的结果!可能是芯片捕获不到,也可能是样本本身变异,造成的大片段缺失。但是这个图的信息就非常有用!
那么,我们该如何画这样的图呢?
首先,我们需要找到需要探究的基因的全部转录信息,及外显子信息!
在hg19_refGene.txt里面会有,在UCSC里面可以下载,新手可能会比较麻烦,实在不行你去annovar的目录也可以找到!
1
那么,我们根据这个信息,就可以判断该基因的起始终止位点啦
然后用samtools的depth命令去找这个基因的全部片段的测序深度信息
最后再格式化成下面的三列数据
第一列是该外显子的坐标,从1到该外显子的成都
第二列是该外显子在该坐标的测序深度,通过samtools的depth命令得到
最后一列是该外显子的标记,从exon:79一直倒推到exon:1,因为该基因在染色体的负链,所以外显子顺序是反着的!
1 84 exon:79
2 84 exon:79
3 84 exon:79
4 85 exon:79
5 85 exon:79
6 86 exon:79
7 85 exon:79
8 87 exon:79
9 89 exon:79
10 91 exon:79
11 92 exon:79
12 95 exon:79
13 96 exon:79
14 96 exon:79
15 99 exon:79
16 99 exon:79
17 97 exon:79
最后根据这个txt文档,用R语言,很容易就画出上面那样的图片了!
这里面的信息量还是蛮大的!
APOB.NM_000384

 

14

R语言画网络图三部曲之sna

如果只是画网络图,那么只需要把所有的点,按照算好的坐标画出来,然后把所有的连线也画出即可!

其中算法就是,点的坐标该如何确定?Two of the most prominente algorithms (Fruchterman & Reingold’s force-directed placement algorithm and Kamada-Kawai’s)
有一个networkD3的包可以直接画图,但是跳过了确定点的坐标这个步骤,我重新找了一包,可以做到!
作者只是用sna包来得到数据,其实用的是ggplot来画网络图!
需要熟悉network包里面的network对象的具体东西,如何自己构造一个,然后数学sna包如何计算layout即可
解读这个包,也可以自己画网络图,代码如下:
plot(plotcord)
text(x=plotcord$X1+0.2,y=plotcord$X2,labels = LETTERS[1:10])
for (i in 1:10){
  for (j in 1:10){
    if(tmp[i,j]) lines(plotcord[c language="(i,j),1"][/c],plotcord[c language="(i,j),2"][/c])
  }
}
当然,我们还没有涉及到算法,就是如何生成plotcord这个坐标矩阵的!
大家看下面这个示意图就知道网络图是怎么样画出来的了,首先我们有一些点,它们之间有联系,都存储在networData这个数据里面,是10个点,共9个连接,然后我用reshape包把它转换成连接矩阵,理论上10个点的两两相互作用应该有100条线,但是我们的数据清楚的说明只有9条,所以只有9个1,其余的0代表点之间没有关系。接下来我们用sna这个包对这个连接矩阵生成了这10个点的坐标(这个是重点),最后很简单了,把点和线画出来即可!

1

另外一个例子:
net=network(150, directed=FALSE, density=0.03)
m <- as.matrix.network.adjacency(net) # get sociomatrix  
# get coordinates from Fruchterman and Reingold's force-directed placement algorithm.
plotcord <- data.frame(gplot.layout.fruchtermanreingold(m, NULL)) 
# or get it them from Kamada-Kawai's algorithm: 
# plotcord <- data.frame(gplot.layout.kamadakawai(m, NULL)) 
colnames(plotcord) = c("X1","X2")  ###所有点的坐标,共150个点
edglist <- as.matrix.network.edgelist(net) ##所有点之间的关系-edge ##共335条线
edges <- data.frame(plotcord[edglist[,1],], plotcord[edglist[,2],]) ##两点之间的连线的具体坐标,335条线的起始终止点点坐标
原始代码如下:
library(network)
library(ggplot2)
library(sna)
library(ergm)
clipboard
大家可以试用这个代码,因为它用的ggplot,肯定比我那个简单R作图要好看多了
参考算法文献:
 

 

14

R语言画网络图三部曲之networkD3

首先,我们需要了解一下基础知识:
网络图是为了展示数据与数据之间的联系,在生物信息学领域,一般是基因直接的相互作用关系,或者通路之间的联系!
通俗点说,就是我有一些点,它们之间并不是两两相互联系,而是有部分是有连接的,那么我应该如何把这些点画在图片上面呢?因为这些都并没有X,Y坐标,只有连接关系,所以我们要根据一个理论来给它们分配坐标,这样就可以把它们画出来了,然后也可以对这些点进行连线,连完线后,就是网络图啦!!!
而给它们分配坐标的理论有点复杂,大概类似于物理里面的万有引力和洛仑磁力相结合来给它们分配一个位置,使得总体的能量最小,就是最稳定状态!而通常这个状态是逼近,而不是精确,所以我们其实对同样的数据可以画出无数个网络图,只需使得网络图合理即可!
看这个ppt:http://statmath.wu.ac.at/research/friday/resources_WS0708_SS08/igraph.pdf

基本上就都理解了
画网络图真的好复杂呀!!!
大部分人都是用D3JS来画图:http://bl.ocks.org/mbostock/2706022
一步步讲受力分析图是如何画的:https://github.com/mbostock/d3/wiki/Force-Layout

接下来, 我们直接看看R里面是如何画网络图的,我们首推一个包:networkD3/

这个包非常好用,只需要做好data,然后用它提供的几个函数即可!
重要的是熟悉输入数据是什么,还可以结合shinny包来展示数据,非常好用!!!
具体怎么安装这个R包,我就不讲了,它的github主页上面其实也有说明书,很容易看懂的
最简单的用法,就是构造一个联结矩阵,把所有的连接关系都存储起来,然后直接用一个函数就可以画图啦!
# Plot
library(networkD3)
simpleNetwork(networkData,fontSize=25)
可以看出网络图,就是把所有的点,按照算好的坐标画出来,然后把所有的连线也画出即可!
其中算法就是,点的坐标该如何确定?Two of the most prominente algorithms (Fruchterman & Reingold’s force-directed placement algorithm and Kamada-Kawai’s)

clipboard

但是这个软件有一个弊端就是,生成图片之后,并没有给出这些点的坐标,当然,这种坐标基本上也很少有人需要,可视化就够了!
如果这些点还分组了,而且连接还有权重,那么网络图就复杂一点,比如下面这个:
就不仅仅是需要提供所有的link的信息,link还多了一列,是value,而且还需提供所有的node信息,node多了一列是分组。
clipboard
当然,还有好几个图,大家可以自己慢慢用,自己体会!
sankeyNetwork
sankeyNetwork
radialNetwork
diagonalNetwork
dendroNetwork
也可以把生成的网络图直接保存成网页,动态显示!
十二 25

使用进度条和并行计算来模拟计算赌博输赢概率

http://www.zhihu.com/question/19605599

以前看到过一个赌徒「必胜方法」
有一个广泛流传于赌徒中的“必胜方法”,是关于赌徒悖论极好的说明:一个赌场设有“猜大小”的赌局,玩家下注后猜“大”或者猜“小”,如果输了,则失去赌注,如果赢的话,则获得本金以及0.9倍的利润。 “必胜法”是这么玩的:
(1)押100猜“大”;
(2)如果赢的话,返回(1)继续;
(3)如果输的话则将赌注翻倍后继续猜“大”,因为不可能连续出现“大”,总会有获胜的时候,而且由于赌注一直是翻倍,只要赢一次,就会把所有输掉的钱赢回;
(4)只要赢了,就继续返回(1)。

一个朋友说写了程序来验证正确与否,我感觉蛮有趣的,想想自己也学了不少,也应该实践一下啦!
写出程序不难,就一个递归而已,不过是应该用并行计算,不然算的太慢了
另外一个重点是,如何随机???
[R]
judge=function(l=left,c=count,n=number,w=win){
c=c+1;
if(rnorm(1)>0){
l=l+2^n
n=1 # win
w=w+1
}else{
l=l-2^n
n=n+1 #lose
}
return(c(l,c,n,w))
}
my_fun=function(x){
tmp=judge(0,1,1,0)
for(i in 1:x){
tmp=judge(tmp[1],tmp[2],tmp[3],tmp[4])
print(tmp)
}
return(tmp[1])
}
my_fun(10)
[/R]
第一个函数是根据现在的状态,接受你的本金,第几次赌了,以及第几次连续下注,最后,你总共赢了多少次,这四个参数,然后随机给一个大小概率,这样你的本金会变化,赌的次数会加1
第二个函数是传入我们需要赌多少次,看结果:
> my_fun(10)
[1] -2  2  2  0
[1] 2 3 1 1
[1] 0 4 2 1
[1] -4  5  3  1
[1] 4 6 1 2
[1] 6 7 1 3
[1] 8 8 1 4
[1] 6 9 2 4
[1]  2 10  3  4
[1] 10 11  1  5
[1]  8 12  2  5
[1] 8
如果我们赌11次,可以看到,我最后会剩余8块钱,每次输赢的情况都反应在里面了,可以自己模拟多次看看!
因为我只赌了11次,所以很快,如果我赌1000次,而且还想检验一下10000次模拟结果,就会比较慢了!
我首先使用进度条模拟一下结果,代码如下:
2
还是比较慢的##Time difference of 1.861802 mins
我用了apply,好像时间是节省了一些,不过聊胜于无!
> library(pbapply)
> start=Sys.time()
> results=pbsapply(1:10000,function(i){my_fun(1000)})
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%
> Sys.time()-start  ##9.909524 secs
Time difference of 1.301539 mins
那接下来我们分析一下模拟的结果吧
> summary(results)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 -64580     974     998     985    1020    1110
可以看到,我们平均下来是会赢钱的,而且赢面很大,赢的次数非常多!!!
但是,我们看下面的图就知道,一个很诡异的结果!
而且,我这里用的模拟胜负,并不是很好
3
这其实还只是小批量模拟,如果要模拟百亿次,首先我的笔记本肯定不行,cpu太破了,如果用服务器,就需要用并行计算啦!
##下面是用多核并行计算的代码,大家有兴趣可以自己去玩一下
library(parallel)
cl.cores <- detectCores() 
cl <- makeCluster(cl.cores)
clusterExport(cl, "judge") 
start=Sys.time()
results=parSapply( 
  cl=cl, 
  1:10000,
  my_fun(1000)
)
Sys.time()-start  ##4.260994 secs
stopCluster(cl)


十二 15

用超几何分布检验做富集分析

我们可以直接使用R的bioconductor里面的一个包,GOstats里面的函数来做超几何分布检验,看看每条pathway是否会富集

我们直接读取用limma包做好的差异分析结果

setwd("D:\\my_tutorial\\补\\用limma包对芯片数据做差异分析")

DEG=read.table("GSE63067.diffexp.NASH-normal.txt",stringsAsFactors = F)

View(DEG)

image001

我们挑选logFC的绝对值大于0.5,并且P-value小雨0.05的基因作为差异基因,并且转换成entrezID

probeset=rownames(DEG[abs(DEG[,1])>0.5 & DEG[,4]<0.05,])

library(hgu133plus2.db)

library(annotate)

platformDB="hgu133plus2.db";

EGID <- as.numeric(lookUp(probeset, platformDB, "ENTREZID"))

length(unique(EGID))

#[1] 775

diff_gene_list <- unique(EGID)

这样我们的到来775个差异基因的一个list

首先我们直接使用R的bioconductor里面的一个包,GOstats里面的函数来做超几何分布检验,看看每条pathway是否会富集

library(GOstats)

library(org.Hs.eg.db)

#then do kegg pathway enrichment !

hyperG.params = new("KEGGHyperGParams", geneIds=diff_gene_list, universeGeneIds=NULL, annotation="org.Hs.eg.db",

categoryName="KEGG", pvalueCutoff=1, testDirection = "over")

KEGG.hyperG.results = hyperGTest(hyperG.params);

htmlReport(KEGG.hyperG.results, file="kegg.enrichment.html", summary.args=list("htmlLinks"=TRUE))

结果如下:

image002

但是这样我们就忽略了其中的原理,我们不知道这些数据是如何算出来的,只是由别人写好的包得到了结果罢了。

事实上,这个包的这个hyperGTest函数无法就是包装了一个超几何分布检验而已。

如果我们了解了其中的统计学原理,我们完全可以写成一个自建的函数来实现同样的功能。

超几何分布很简单,球分成黑白两色,数量已知,那么你随机抽有限个球,应该抽多少白球的问题!
公式就是 exp_count=n*M/N
然后你实际上抽了多少白球,就可以计算一个概率值!
换算成通路的富集概念就是,总共有多少基因,你的通路有多少基因,你的通路被抽中了多少基因(在差异基因里面属于你的通路的基因),这样的数据就足够算出上面表格里面所有的数据啦!
tmp=toTable(org.Hs.egPATH)
GeneID2Path=tapply(tmp[,2],as.factor(tmp[,1]),function(x) x)
Path2GeneID=tapply(tmp[,1],as.factor(tmp[,2]),function(x) x)
#phyper(k-1,M, N-M, n, lower.tail=F)
#n*M/N
diff_gene_has_path=intersect(diff_gene_list,names(GeneID2Path))
n=length(diff_gene_has_path) #321 # 这里算出你总共抽取了多少个球
N=length(GeneID2Path) #5870  ##这里算出你总共有多少个球(这里是错的,有多少个球取决于背景基因!一般是两万个)
options(digits = 4)
for (i in names(Path2GeneID)){
 M=length(Path2GeneID[[i]])  ##这个算出你的所有的球里面,白球有多少个
 exp_count=n*M/N  ###这里算出你抽取的球里面应该多多少个是白色
 k=0         ##这个k是你实际上抽取了多少个白球
 for (j in diff_gene_has_path){
 if (i %in% GeneID2Path[[j]]) k=k+1
 }
 OddsRatio=k/exp_count
 p=phyper(k-1,M, N-M, n, lower.tail=F)  ##根据你实际上抽取的白球个数,就能算出富集概率啦!
 print(paste(i,p,OddsRatio,exp_count,k,M,sep="    "))
}
随便检查一下,就知道结果是一模一样的!

 

30

R语言也可以用hash啦

本来想着是如何习惯R里面的list对象,来实现hash的功能,无意中发现了居然还有这个包

https://cran.r-project.org/web/packages/hash/hash.pdf

我简单看了看文档,的确跟perl里面的hash功能类似,非常好用。

创建一个hash很简单

h <- hash( keys=letters, values=1:26 )

h <- hash( letters, 1:26 )

类似于下面的列表

L=setNames(as.list(LETTERS),1:26)

如果是列表要提取keys需要用names函数,如果需要提取values,需要用unlist函数,而用了hash之后,这两个函数就可以独自运行啦

还有很多其它函数,其实在list中也可以实现,主要是看你对哪种语法更熟悉,感觉自己现在编程能力差不多算是小有所成了,看什么都一样了,要是以前学R的时候看到了这个hash包,我肯定会很兴奋的!

clear signature(x = "hash"): Remove all key-value pairs from hash
del signature(x = "ANY", hash = "hash"): Remove specified key-value pairs from hash
has.key signature(key = "ANY", hash = "hash"): Test for existence of key
is.empty signature(x = "hash"): Test if no key-values are assigned
length signature(x = "hash"): Return number of key-value pairs from the hash
keys signature(hash = "hash"): Retrieve keys from hash
values signature(x = "hash"): Retrieve values from hash
copy signature(x = "hash"): Make a copy of a hash using a new environment.
format signature(x = "hash"): Internal function for displaying hash

 

30

R里面list对象和AnnDbBimap对象区别

AnnDbBimap对象是R里面的bioconductor系列包的基础对象,在探针数据里面会包装成ProbeAnnDbMap,跟go通路相关又是GOTermsAnnDbBimap对象。

但是它都是AnnDbBimap对象衍生过来的

主要存在于芯片系列的包和org系列的包,其实AnnDbBimap对象就是list对象的包装,比如下面这些例子:

ls("package:hgu133plus2.db")

 [1] "hgu133plus2"              "hgu133plus2.db"           "hgu133plus2_dbconn"
 [4] "hgu133plus2_dbfile"       "hgu133plus2_dbInfo"       "hgu133plus2_dbschema"
 [7] "hgu133plus2ACCNUM"        "hgu133plus2ALIAS2PROBE"   "hgu133plus2CHR"
[10] "hgu133plus2CHRLENGTHS"    "hgu133plus2CHRLOC"        "hgu133plus2CHRLOCEND"
[13] "hgu133plus2ENSEMBL"       "hgu133plus2ENSEMBL2PROBE" "hgu133plus2ENTREZID"
[16] "hgu133plus2ENZYME"        "hgu133plus2ENZYME2PROBE"  "hgu133plus2GENENAME"
[19] "hgu133plus2GO"            "hgu133plus2GO2ALLPROBES"  "hgu133plus2GO2PROBE"
[22] "hgu133plus2MAP"           "hgu133plus2MAPCOUNTS"     "hgu133plus2OMIM"
[25] "hgu133plus2ORGANISM"      "hgu133plus2ORGPKG"        "hgu133plus2PATH"
[28] "hgu133plus2PATH2PROBE"    "hgu133plus2PFAM"          "hgu133plus2PMID"
[31] "hgu133plus2PMID2PROBE"    "hgu133plus2PROSITE"       "hgu133plus2REFSEQ"
[34] "hgu133plus2SYMBOL"        "hgu133plus2UNIGENE"       "hgu133plus2UNIPROT"

那么我们可以随便挑选包中的一个数据分析一下

x <- hgu133plus2SYMBOL

xlist=as.list(x)

我们查看X对象,可知,它是object of class "ProbeAnnDbMap",而这个对象,就是常见的list对象,被包装了一下, 只有我们明白了它和list对象到底有什么区别,才算是真正搞懂了这一系列包

但是这个ProbeAnnDbMap对象,在GO等包里面会被包装成更复杂的对象-GOTermsAnnDbBimap,但是对他们的理解都大同小异。

我们先回顾一下在R语言里面的list的基础知识:

R 的 列表(list)是一个以对象的有序集合构成的对象。 列表中包含的对象又称为它的分量(components)。

分量可以是不同的模式或者类型, 如一个列表可以包括数值向量,逻辑向量,矩阵,复向量, 字符数组,函数等等

如果你会perl的话,可以把它理解成hash。

分量常常会被编号的(numbered),并且可以利用它来 访问分量

列表的分量可以被命名,这种情况下 可以通过名字访问。

特别要注意一下 Lst[[1]] 和 Lst[1] 的差别。 [[...]] 是用来选择单个 元素的操作符,而 [...] 是一个更为一般 的下标操作符。

因此前者得到的是列表 Lst 中的第一个对象, 并且含有分量名字的命名列表(named list)中分量的名字会被排除在外的。

后者得到的则是列表 Lst 中仅仅由第一个元素 构成的子列表。如果是命名列表, 分量名字会传给子列表的。

那么接下来我们就看看x和xlist的区别。

它们里面的数据都是affymetrix公司出品的人类的hgu133plus2芯片的探针ID与基因symbol的对应关系

如果我想拿到所有的探针ID,那么对于AnnDbBimap对象,需要用mappedkeys(x),对于普通的list对象,需要用names(xlist).

对于普通的list对象,如果我想看前几个元素,直接head就可以了,但是对于AnnDbBimap对象,数据被封装好了,需要先as.list,然后才能head

mapped_probes <- mappedkeys(x)

PID2=head(mapped_probes)

那么,如果我们想根据以下探针ID来查看它们在这些数据里面被对应着哪些基因symbol 呢?

> PID2 #这是一串探针ID,后面的操作都需要用的

[1] "1053_at"   "117_at"    "121_at"    "1255_g_at" "1316_at"   "1320_at"

如果是对于AnnDbBimap对象,我们可以用mget函数来操作,取多个探针的对应基因symbol

accnum <- mget(PID2, env=hgu133plus2ACCNUM);

gname <- mget(PID2, env=hgu133plus2GENENAME)

gsymbol <- mget(PID2, env=hgu133plus2SYMBOL)

mget函数返回的就是普通的list函数了,可以直接查看了。

如果是对于普通的list对象,我们想取多个探针的对应基因symbol也是非常简单的,xlist[PID2]即可。

那么我们不禁有问了,既然它们两个功能完全一样,何苦把它包装成一个对象了,我直接操作list对象不就好了,学那么多规矩干嘛?

所以,重点就来了

>  length(mapped_probes)

[1] 42125

> length(names(xlist))

[1] 54675

看懂了吗?

 

但是,事实上用处也不大,你觉得下面这两个有区别吗?

SYMBOL <- AnnotationDbi::as.list(hgu133plus2SYMBOL)

SYMBOL <- SYMBOL[!is.na(SYMBOL)];

 

x <- hgu133plus2SYMBOL

mapped_probes <- mappedkeys(x)

SYMBOL <- AnnotationDbi::as.list(x[mapped_probes])

 

PS,在R里面创建一个list对象是非常简单的

The setNames() built-in function makes it easy to create a hash from given key and value lists.(Thanks to Nick K for the better suggestion.)

Usage: hh <- setNames(as.list(values), keys)

Example:

players <- c("bob", "tom", "tim", "tony", "tiny", "hubert", "herbert")
rankings <- c(0.2027, 0.2187, 0.0378, 0.3334, 0.0161, 0.0555, 0.1357)
league <- setNames(as.list(rankings), players)

29

gene的各种ID转换终结者-bioconductor系列包

经常会有人问这样的问题I have list of 10,000 Entrez IDs and i want to convert the multiple Entrez IDs into the respective gene names. Could someone suggest me the way to do this?等等类似的基因转换,能做的基因转换的方法非常多,以前不懂编程的时候,都是用各种网站,而最常用的就是ensembl的biomart了,它支持的ID非常多,高达几百种,好多ID我到现在都不知道是什么意思。

现在学会编程了,我比较喜欢的是R的一些包,是bioconductor系列,一般来说,其中有biomart,org.Hs.eg.db,annotate,等等。关于biomart我就不再讲了,我前面的博客至少有七八篇都提到了它。本次我们讲讲简单的, 我就以把gene entrez ID转换为gene symbol 为例子把。

当然,首先要安装这些包,并且加载。

if("org.Hs.eg.db" %in% rownames(installed.packages()) == FALSE) {source("http://bioconductor.org/biocLite.R");biocLite("org.Hs.eg.db")}
suppressMessages(library(org.Hs.eg.db))  我比较喜欢这样加载包

library(annotate) #一般都是这样加载包

如果是用org.Hs.eg.db包,首先你只需要读取你的待转换ID文件,构造成一个向量,tmp,然后只需要symbols <- org.Hs.egSYMBOL[as.character(tmp)]就可以得到结果了,返回的symbols是一个对象,需要用toTable这个函数变成数据框。但是这样转换容易出一些问题,比如如果你的输入数据tmp,里面含有一些无法转换的gene entrez ID,就会报错。

而且它支持的ID转换很有限,具体看看它的说明书即可:https://www.bioconductor.org/packages/release/data/annotation/manuals/org.Hs.eg.db/man/org.Hs.eg.db.pdf

org.Hs.eg.db
org.Hs.eg_dbconn
org.Hs.egACCNUM
org.Hs.egALIAS2EG
org.Hs.egCHR
org.Hs.egCHRLENGTHS
org.Hs.egCHRLOC
org.Hs.egENSEMBL
org.Hs.egENSEMBLPROT
org.Hs.egENSEMBLTRANS
org.Hs.egENZYME
org.Hs.egGENENAME
org.Hs.egGO
org.Hs.egMAP
org.Hs.egMAPCOUNTS
org.Hs.egOMIM
org.Hs.egORGANISM
org.Hs.egPATH
org.Hs.egPMID
org.Hs.egREFSEQ
org.Hs.egSYMBOL
org.Hs.egUCSCKG
org.Hs.egUNIGENE
org.Hs.egUNIPROT

如果是用annotate包,首先你还是需要读取你的待转换ID文件,构造成一个向量,tmp,然后用getSYMBOL(as.character(tmp), data='org.Hs.eg')这样直接就返回的还是以向量,只是在原来向量的基础上面加上了names属性。说明书:http://www.bioconductor.org/packages/3.3/bioc/manuals/annotate/man/annotate.pdf

然后你可以把转换好的向量写出去,如下:

1 A1BG
2 A2M
3 A2MP1
9 NAT1
10 NAT2
12 SERPINA3
13 AADAC
14 AAMP
15 AANAT
16 AARS

PS:如果是芯片数据,需要把探针的ID转换成gene,那么一般还需要加载特定芯片的数据包才行:

platformDB <- paste(eset.mas5@annotation, ".db", sep="") #这里需要确定你用的是什么芯片
cat("the annotation is ",platformDB,"\n")
if(platformDB %in% rownames(installed.packages()) == FALSE) {source("http://bioconductor.org/biocLite.R");tmp=try(biocLite(platformDB))}
library(platformDB, character.only=TRUE)
probeset <- featureNames(eset.mas5)
rowMeans <- rowMeans(exprSet)

library(annotate) # lookUp函数是属于annotate这个包的
EGID <- as.numeric(lookUp(probeset, platformDB, "ENTREZID"))

29

使用GEOmetadb包来获取对应GEO数据的实验信息

理论上我前面提到的GEOquery包就可以根据一个GSE索引号来获取NCBI提供的所有关于这个GSE索引号的数据了,包括metadata,表达矩阵,soft文件,还有raw data

但是很多时候,那个metadata并不是很整齐,而且一个个下载太麻烦了,所以就需要用R的bioconductor的另一个神奇的包了GEOmetadb

它的示例:http://bioconductor.org/packages/devel/bioc/vignettes/GEOmetadb/inst/doc/GEOmetadb.R

里面还是很多数据库基础知识的
代码托管在github,它的示例代码是这样连接数据库的:
library(GEOmetadb)
if(!file.exists('GEOmetadb.sqlite')) getSQLiteFile()
file.info('GEOmetadb.sqlite')
con <- dbConnect(SQLite(),'GEOmetadb.sqlite')
dbDisconnect(con)
但是一般不会成功,因为这个包把它的GEOmetadb.sqlite文件放在了国外网盘共享,在国内很难访问,推荐大家想办法下载到本地
tmp2
用这个代码就会成功了,需要自己下载GEOmetadb.sqlite文件然后放在指定目录:/path/GEOmetadb.sqlite 需要自己修改
我们的diabetes.GEO.list文件内容如下:
GSE1009
GSE10785
GSE1133
GSE11975
GSE121
GSE12409
那么会产生的表格文件如下:共有32列数据信息,算是蛮全面的了
tmp
22

R语言中的排序,集合运算,reshape,以及merge总结

一直以来我都是随便看了点R的编程教程,因为我学了一点点C,所以还算有基础,现在基本上简单看看教程就能懂一门语言了,区别只是熟练度而已。R用得比较多,所以还算擅长,但是很多快捷应用的地方,我总是寄希望于到时候再查资料,所以没能用心的记住,这次花了点时间好好整理了一下R里面关于数据操作的重点,我想,以后再碰到类似的数据处理要求,应该很快能解决了把。

首先看看排序:

在R中,和排序相关的函数主要有三个:sort(),rank(),order()。

sort(x)是对向量x进行排序,返回值排序后的数值向量。

rank()是求秩的函数,它的返回值是这个向量中对应元素的“排名”。

order()的返回值是对应“排名”的元素所在向量中的位置。

其中sort(x)等同于x[order(x)]

下面以一小段R代码来举例说明:

> x<-c(97,93,85,74,32,100,99,67)

> sort(x)

[1]  32  67  74  85  93  97  99 100

> order(x)

[1] 5 8 4 3 2 1 7 6

> rank(x)

[1] 6 5 4 3 1 8 7 2

> x[order(x)]

[1]  32  67  74  85  93  97  99 100

其中比较有用的order,它可以用来给数据框进行排序

dat[order(dat[,1]),] 以该数据框的第一列进行排序

dat[order(dat[,1],dat[,2]),] 以该数据框的第一列为主要次序,第二列为次要序列进行排序

 

然后我们看看集合运算:

在R里面除了简单的对两个向量求交集并集补集之外,比较重要的就是match和 %in% 了,需要重点讲讲。

#首先对集合A,B,C赋值

> A<-1:10

> B<-seq(5,15,2)

> C<-1:5

> #求A和B的并集

> union(A,B)

[1]  1  2  3  4  5  6  7  8  9 10 11 13 15

> #求A和B的交集

> intersect(A,B)

[1] 5 7 9

> #求A-B

> setdiff(A,B)

[1]  1  2  3  4  6  8 10

> #求B-A

> setdiff(B,A)

[1] 11 13 15

> #检验集合A,B是否相同

> setequal(A,B)

[1] FALSE

> #检验元素12是否属于集合C

> is.element(12,C)

[1] FALSE

> #检验集合A是否包含C

> all(C%in%A)

[1] TRUE

> all(C%in%B)

从上面可以看到%in%这个操作符只返回逻辑向量TRUE 或者FALSE,而且返回值应该与%in%这个操作符前面的向量程度相等。也就是说它相当于遍历了C里面的一个个元素,判断它们是否在B中出现过,然后返回是或者否即可。

而match(C,B)的结果就很不一样了,它的返回结果同样与前面的向量等长,但是它并非返回逻辑向量,而是遍历了C里面的一个个元素,判断它们是否在B中出现过,如果出现就返回在B中的索引号,如果没有出现,就返回NA

>B

[1]  5  7  9 11 13 15

>C

[1] 1 2 3 4 5

>match(C,B)

[1] NA NA NA NA  1

>C%in%B

[1] FALSE FALSE FALSE FALSE  TRUE

 接下来我们看看reshape:

这是一个需要安装的包,起得就是R里面最经典的把长型数据变宽,和把宽数据拉长的作用。

其中melt函数是把很宽的数据拉长,它就是需要指定几列数据是保证不被融合的, 其余每一列数据都必须被融合到一列了,融合后的这一列数据每个元素旁边就用列名来标记该数据来自于哪一列。

# example of melt function
library(reshape)
mdata <- melt(mydata, id=c("id","time"))

融合后的数据如下:

id time variable value
1 1 x1 5
1 2 x1 3
2 1 x1 6
2 2 x1 2
1 1 x2 6
1 2 x2 5
2 1 x2 1
2 2 x2 4

可以看到variable列里面有两个不同的元素,说明是把旧数据中的两列给融合了,融合后的一个很长的列就是value

而cast函数的功能就是把刚才融合好的数据给还原。

# cast the melted data
# cast(data, formula, function)
subjmeans <- cast(mdata, id~variable, mean)
timemeans <- cast(mdata, time~variable, mean)

可以看到它们返回的结果是:

subjmeans

id x1 x2
1 4 5.5
2 4 2.5

timemeans

time x1 x2
1 5.5 3.5
2 2.5 4.5

可以看到cast函数比较复杂一点,formula公式右边的变量是需要拆开的variable,这一列变量有多少不重复元素,就新增多少列,左边的变量是行标记了,其余所有数据都会被计算一下再放在合适的位置。

在reshape2这个包里面还进化出来dcast和acast函数,功能大同小异。

 

最后我们来看看merge函数:

这个函数的功能非常强大,类似于SQL语句里面的join系列函数

测试数据如下,它们这两个表的连接是作者名

Capture1

 

如果要实现类似sql里面的inner join 功能,则用代码

m1 <- merge(authors, books, by.x = "surname", by.y = "name")

如果要实现left join功能则用代码

m1 <- merge(authors, books, by.x = "surname", by.y = "name",all.x=TRUE)

right join功能代码

m1 <- merge(authors, books, by.x = "surname", by.y = "name",all.y=TRUE)

all join功能代码

m1 <- merge(authors, books, by.x = "surname", by.y = "name",all=TRUE)

关于单变量匹配的总结就是这些,但对于多变量匹配呢,例如下面两个表,需要对k1,k2两个变量都相等的情况下匹配

x <- data.frame(k1 = c(NA,NA,3,4,5), k2 = c(1,NA,NA,4,5), data = 1:5)

y <- data.frame(k1 = c(NA,2,NA,4,5), k2 = c(NA,NA,3,4,5), data = 1:5)

匹配代码如下merge(x, y, by = c("k1","k2"))  #inner join

另外一个多行匹配的例子如下:

Capture2

我们的测试数据如上,这两个表的连接在于作者名。下面这两个语句等价

merge(authors, books, by=1:2)

merge(authors, books, by.x=c("FirstName", "LastName"),

by.y=c("AuthorFirstName", "AuthorLastName"),

all.x=TRUE)

都可以把两张表关联起来。

当然,在我搜索资料的时候,发现了另外一个解决问题的方法:

A[with(A, paste(C1, C2, sep = "\r")) %in% with(B, paste(C1, C2, sep="\r")), ]

 

 

参考:http://blog.sina.com.cn/s/blog_6caea8bf0100spe9.html

http://blog.sina.com.cn/s/blog_6caea8bf010159dt.html

http://blog.csdn.net/u014801157/article/details/24372441

http://www.statmethods.net/management/reshape.html

https://docs.tibco.com/pub/enterprise-runtime-for-R/1.5.0_may_2013/TERR_1.5.0_LanguageRef/base/merge.html

http://r.789695.n4.nabble.com/Matching-multiple-columns-in-a-data-frame-td890832.html

http://bbs.pinggu.org/thread-3234639-1-1.html

http://www.360doc.com/content/14/0821/13/18951041_403561544.shtml

http://developer.51cto.com/art/201312/423612.htm

22

用R和mysql把基因对应的最大表达量探针挑出来

懂点芯片数据分析的都应该知道,芯片设计的时候,对一个基因设计了多个探针,这样设计是为了更好的捕获某些难以发现的基因,或者重点研究某些基因。
但是对我们的差异分析不方便,所以我们只分析哪些有对应了entrez ID的探针,而且对每个entrez ID,我们只需要挑选它表达量最高的那个探针。
所以就演化为一个编程问题:分组求最大值,多公共列合并!
如果是在R语言里面,那么首先这个table的表示形式如下
> esetDataTable[1:10,c(7,8)]
EGID rowMeans
1000_at 5595 1840.04259751826
1001_at 7075 799.075414422572
1002_f_at 1557 50.4884096416177
1003_s_at 643 142.372008051308
1004_at 643 211.65300963049
1005_at 1843 4281.29318032004
1006_at 4319 38.5784289213085
1007_s_at NA 1489.98158531843
1008_f_at 5610 4013.576753977
1009_at 3094 3070.50648167305
我们首先看看一个R语言函数处理方式吧,这个是比较容易想到的算法,但是用到了循环,非常的不经济,计算量很大。

Capture1
因为里面涉及到了双重循环。我进行了人工计时,这个程序耗费了一分钟十二秒,程序里面的计时器有点问题。

然后我再讲一个精简版的算法
dat=esetDataTable[,c(7,8)]
dat=as.data.frame(apply(dat,2,as.numeric))
dat$prob=rownames(esetDataTable)
首先可以得到需要提取的数据所在行的两个值
match_row=aggregate(dat,by=list(dat[,1]),max)
类似于这句SQL语句:SELECT max(a.rowMeans) as val, a.EGID FROM test.esetDataTable a group by a.EGID
现在要根据match_row表去原表esetDataTable里面提取我们的探针ID数据。

Capture2

这样就完美解决了问题,我们的合并后的数据的prob列,就是前面那个函数计算了一分多钟的返回的非冗余探针ID向量,relevantProbesets,但是这次只花了不到一秒钟。
tmp_prob=merge(dat,match_row,by=c("EGID","rowMeans"))
setdiff(as.character(relevantProbesets),as.character(tmp_prob$prob))
length(union(as.character(relevantProbesets),as.character(tmp_prob$prob)))
setdiff(as.character(tmp_prob$prob),as.character(relevantProbesets))
我顺便检查了一下上面那个复杂的R函数跟我这次精简版的结果,发现这次才是对的,上面那个错了。
你们能发现上面那个为什么错了吗?

如果是在mysql里面它的表现形式如下;
mysql> select row_names,EGID,rowMeans from esetDataTable order by EGID limit 10;
+------------+-------+------------------+
| row_names | EGID | rowMeans |
+------------+-------+------------------+
| 38912_at | 10 | 85.8820246154773 |
| 41654_at | 100 | 301.720067595558 |
| 907_at | 100 | 273.100008206028 |
| 2053_at | 1000 | 354.207060199715 |
| 2054_g_at | 1000 | 33.8472900312781 |
| 40781_at | 10000 | 425.007640082848 |
| 35430_at | 10001 | 152.885791914329 |
| 35431_g_at | 10001 | 181.915087187117 |
| 35432_at | 10001 | 184.869017764782 |
| 31366_at | 10002 | 44.9716205901791 |
+------------+-------+------------------+
10 rows in set (0.05 sec)

如果要用SQL来做同样的事情需要下面这个语句,这个就非常简单啦!
select b.*
from test.esetDataTable b
inner join (
SELECT max(a.rowMeans) as val, a.EGID FROM test.esetDataTable a group by a.EGID
) as c on b.EGID=c.EGID and b.rowMeans=c.val
结果是:8640 rows in set (4.56 sec) 看起来mysql还没有R语言快速,但是这个mysql语句很明显也不是很高效,但是我的mysql水平有限。
稍微解释一下这个mysql语句,其中SELECT max(a.rowMeans) as val, a.EGID FROM test.esetDataTable a group by a.EGID类似于R里面的match_row=aggregate(dat,by=list(dat[,1]),max),就是把每个entrez ID对应着的最大值提取出来成一个新的表
而inner join on b.EGID=c.EGID and b.rowMeans=c.val 就是我们的tmp_prob=merge(dat,match_row,by=c("EGID","rowMeans")) 根据两列来合并两个数据框