原位作者:瓦莱丽·奥根特,马丁摩根
提交作者:马丁摩根(martin.morgan@roswellpark.org.)日期:2016年6月25日
本节的目标是强调编写正确、健壮和高效的R代码的实践。
完全相同的()
,All.Equal()
)NA.
价值观,......system.time ()
或者Microbenchmark.包中。rprof()
功能或包装函数lineprof.或者4月份矢量化 - 在向量上运行,而不是明确的循环
x < - 1:10 log(x)##不是for(i在seq_along中)x [i] < - log(x [i])
## [1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379 1.7917595 1.9459101 ## [8] 2.0794415 2.1972246 2.3025851
预先分配内存,然后填写结果
结果< - numeric(10)结果[1] < - runif(1)for(i在2:length(结果))结果[i] < - runif(1)*结果[i-1]结果
## [6] 1.391109e-03 1.085354e-04 8.256891e-05 6.167133e-05 4.673066e-05
为了
循环lm.fit()
而不是反复拟合相同的设计矩阵。表格()
,rowsums()
和朋友,%在%
,......这是一个明显低效的功能:
f0 < - 函数(n,a = 2){## stopfnot(是.integer(n)&&(长度(n)== 1)&& ##!是.na(n)&&(n> 0))结果< - numeric()for(i在seq_len(n)中)结果[[i]] < - a * log(i)结果}
用system.time ()
调查该算法如何衡量n
,专注于经过的时间。
system.time (f0 (10000))
##用户系统经过## 0.139 0.000 0.139
n < - 1000 * seq(1,20,2)t < - sapply(n,function(i)system.time(f0(i))[[3]]图(t〜n,type =“b”)
记住当前的“正确”值,以及一个近似的时间
N <- 10000系统。预计时间(< - f0 (n))
##用户系统运行## 0.155 0.000 0.156
头(预期)
## [1] 0.000000 1.386294 2.197225 2.772589 3.218876 3.583519
修改呼吸常见乘法器的功能,一个
, 跳出循环。确保“优化”和原始计算的结果相同。使用Microbenchmark.包以比较两个版本
F1 <- function(n, a=2) {result <- numeric() for (i in seq_len(n)) result[[i]] <- log(i) a * result} identical(expected, F1 (n))
# # [1]
库(MicroBenchmark)Microbenchmark(F0(n),f1(n),times = 5)
##单位:毫秒为:毫秒敏捷LQ均值UQ MAX NEVAL ## F0(n)118.6033 123.8989 132.8397177.4337 5
采用“预先分配和填充”策略
F2 <- function(n, a=2) {result <- numeric(n) for (i in seq_len(n)) result[[i]] <- log(i) a * result} identical(expected, F2 (n))
# # [1]
Microbenchmark(F0(N),F2(N),时间= 5)
##单位:毫秒## EXPR分钟LQ平均中值最大UQ ## neval F0(n)的136.82808 180.08703 172.27453 181.08084 181.26852 182.1082 5 ## F2(n)的18.75233 18.85918 20.29981 20.28972 20.37353 23.2243 5
使用一个*应用()
避免必须明确地预先分配的功能,并使矢量化更加明显。
F3 < - 函数(n,a = 2)a * sapply(seq_len(n),log)相同(预期,f3(n))
# # [1]
Microbenchmark(F0(N),F2(N),F3(N),时间= 10)
##单位:毫秒## EXPR分钟LQ平均中值最大UQ ## F0(n)的134.451852 137.003841 171.20652 183.653188 188.31813 191.75448 ## F2(n)的18.745654 18.833771 20.50144 20.254524 20.88116 23.44838 ## F3(n)的9.467853 9.651863 10.05424 9.729817 10.56676 11.24802## Neval ## 10#10 ## 10
现在代码显示在一行中,很明显它可以很容易地向量化。抓住机会将其矢量化:
F4 < - 函数(n,a = 2)a * log(seq_len(n))相同(预期,f4(n))
# # [1]
Microbenchmark(F0(n),f3(n),f4(n),时间= 10)
##单位:微秒## EXPR分钟LQ平均中值最大UQ ## F0(n)的135787.889 137468.593 170961.713 184137.111 187689.288 188119.542 ## F3(n)的8705.995 9402.749 9507.574 9554.713 9774.741 9841.998 ## F4(N)517.837 522.898 524.170 525.450 526.068 526.819## Neval ## 10#10 ## 10
f4 ()
绝对似乎是胜利者。它如何扩展n
?(重复几次)
n < - 10 ^(5:8)#100x大于f0 t < - sapply(n,function(i)system.time(f4(i))[[3]])绘图(t〜n,log =“xy“,type =”b“)
对不同响应模式的解释?
得到教训:
*应用()
功能有助于避免需要明确的预分配,并为矢量化的机会更加明显。这可能会出现小的性能成本,但通常是值得的当数据太大而无法装入内存时,我们可以以块的形式遍历文件,或者按字段或基因组位置来划分数据子集。
迭代 - 块明智 -打开()
,阅读块(s),关闭()
.——例如,屈服
争论RSAMTOOLS :: BAMFILE()
- 框架:GenomicFiles :: DreambyByield()
限制—对感兴趣的列和/或行进行限制—利用特定于领域的格式—BAM文件和Rsamtools: ScanBamParam ()
- BAM文件和RSAMTOOLS :: PILPPALAM()
- VCF文件和VariantAnnotation :: ScanVCFParam()
-使用数据库
迭代文件:`genomicfiles :: dreambybyyield()
suppressPackageStartUpMessages({库(基因组)库(基因组)库(RSAMTools)库(TXDB.hsapiens.ucsc.hg19.knowngene)})产量< - #如何输入数据函数的下一个块(x,...){readgalignments(x)} map < - #到每个块函数(value,...,roi){olaps < - sopeoverlaps(value,roi,type =“内部”,ignore.strand = true)count < -Tabulate(主题(OLAPS),主管长度(OLAP))符合姓(计数,名称(ROI))}减少<--` +`#如何组合映射的块
改进:“产量厂”跟踪输入有多少录
exitingFactory < - #返回具有本地状态函数(){n_records < - 0l函数(x,...){aln < - readgalignments(x)n_records << - n_records + length(aln)消息(n_records)aln}}
感兴趣的区域,像bam文件中的染色体一样命名。
Exbytx < - Exonsby(txdb.hsapiens.ucsc.hg19.knowngene,“tx”)fl < - “/ home/ubuntu/data/vobencha/largedata/srarchive/hg19_alias.tab”map0 < - read.delim(fl,header= false,stringsasfactors = false)seqlevels(exbytx,force = true)< - setNames(map0 $ v1,map0 $ v2)
一个遍历bam文件的函数。
count1 < - 函数(filename,roi){message(文件名)##创建和打开BAM文件BF < - BAMFILE(FILENAME,ExuctionSize = 1000000)DreambyByield(BF,EucketFactory(),Map,Defile,ROI = ROI)}
在行动中
BAM < - “/home/ubuntu/data/vobencha/largedata/srarchive/srr1039508_sorted.bam”count < - count1(bam,exbytx)
类型 | 示例使用 | 的名字 | 包裹 |
---|---|---|---|
。床 | 范围注释 | Bedfile() |
rtracklayer. |
。假发 | 覆盖范围 | wigfile() ,bigwigfile() |
rtracklayer. |
.gtf | 记录模型 | gtffile() |
rtracklayer. |
makeTxDbFromGFF () |
GenomicFeatures | ||
.2bit | 基因组序列 | twobitfile() |
rtracklayer. |
.fastq | 读取和品质 | fastqfile() |
ShortRead |
.BAM. | 对齐的阅读 | BamFile () |
Rsamtools |
.tbx. | 索引标签分隔 | tabixfile() |
Rsamtools |
.vcf | 变体呼叫 | VcfFile () |
VariantAnnotation. |
## rtracklayer menagerie suppresspackagestartupmessages(库(rtracklayer))名称(getClass(“rtlfile”)@子类)
## [1] "UCSCFile" "GFFFile" "BEDFile" ## [4] "WIGFile" "BigWigFile" "ChainFile" ## [7] "TwoBitFile" "FastaFile" TabSeparatedFile" ## [10] "CompressedFile" "GFF1File" "GFF2File" ## [13] "GFF3File" "BEDGraphFile" "BED15File" ## [19] "GTFFile" "GVFFile" "GZFile" ## [22] "BGZFile" "BZ2File" "XZFile"
笔记
打开()
,关闭()
,进口()
/产量()
/读*()
.Bai.
bam指数);选择(“列”);限制(“行”)* filelist()
班级
DreambyByield()
-遍历单个大文件bplapply ()
(BiocParallel) - 并行对多个文件执行独立操作GenomicFiles ()
reduceByRange ()
,reduceByFile ()
:折叠地图入摘要表示vcfstack()
VcfStack ?
几个警告 -
迭代/限制性技术在控制下保持内存要求,而并行评估在节点上分配计算负载。请记住,并行计算仍然受到每个节点上可用的内存量的限制。
在分布式存储器中计算时,在群集中设置和撕毁群集时,有开销。对于小的计算,并行开销可能超过性能没有提高的好处。
从并行执行中获益最多的作业是cpu密集型的,操作的数据块适合内存。
BiocParallel提供标准化接口,用于并行评估,并支持主要并行计算样式:叉子和过程在单个计算机上,ad hoc集群,批量调度程序和云计算。默认,BiocParallel选择适合操作系统的并行后端,并在UNIX,MAC和Windows中支持。
一般想法:
bplapply ()
代替lapply()
争论BPPARAM.
影响并行计算发生的方式
MulticoreParam()
:单个(非窗口)机器上的线程SnowParam()
:在相同或不同的机器上的过程batchjobsparam()
:集群上的资源调度程序这个小示例激发了并行执行的使用,并演示了如何使用bplapply ()
可以是一下Lapply.
.
用system.time ()
探索这需要多长时间执行n
从1到10增加完全相同的()
和Microbenchmark.比较替代方案F0()
和F1()
为了正确性和性能。
乐趣
睡1秒钟,然后返回我
.
图书馆(Biocparallel)有趣< - 函数(i){sys.sleep(1)i} ##串行f0 < - 函数(n)lapply(seq_len(n),fun)##并行f1 < - function(n)bppppply(SEQ_LEN(N),乐趣)
BPREDO
BiocParallel“捕获并返回”错误以及成功的结果。本练习演示了如何访问回溯()
失败的任务以及如何使用“bpredo”重新运行失败的任务。有关错误处理,日志记录和调试的完整详细信息错误,日志和调试小插图。
param <- MulticoreParam(workers = 3)
打电话给sqrt ()
在“X”功能;第二个元素是一个字符,将抛出和错误。
X <- list(1, "2", 3) res <- bplapply(X, sqrt, BPPARAM = param)
##错误:生物竞争错误##元素索引:2 ##第一个错误:数学函数的非数字参数
还可以捕获错误和部分计算的结果
RES < - BPTRY(BPLAPPLY(X,SQRT,BPPARAM = PARAM))RES
## [[1]] ## [1] 1 ## ## [[2]] ## ## traceback()作为'attr(x,“回溯”)'## ## [[3]] ## [1] 1.732051
通过重复呼叫重新运行失败的结果bplapply ()
这次通过校正的输入数据和部分结果为“BPREDO”。只重新运行失败的值。
x.redo < - list(1,2,3)Bpprapply(x.redo,sqrt,bpredo = res)
##恢复以前的计算......
## [[1]] ## [1] 1 ## ## [[2]] ## [1] 1.414214 ### [[3]] ## [1] 1.732051
或者,切换到aSerialParam()
并调试导致错误的特定元素。
> Fun =函数(i){browser();sqrt(i)}> bpppply(x,fun,bpredo = res,bpparam = serialparam())恢复以前的计算...从:fun(...)浏览[1]>调试#1:sqrt(i)浏览[2]> i [1]“2”浏览[2]> i = 2浏览[2]> c [1]] [1] 1 [[2]] [1] 1.414214 [[3]][1] 1.732051
BiocParallel使用futile.logger包的日志记录。该包有一个灵活的系统,用于过滤不同严重性阈值的消息,如INFO、DEBUG、ERROR等(所有阈值的列表请参阅?bpthreshold手册页)。BiocParallel捕获以fution.logger格式编写的消息以及写入stdout和stderr的消息。
这个函数进行一些参数检查,并具有DEBUG、WARN和info级别的日志消息。
有趣< - 函数(i){flog.debug(Paste0(“I'的值:”,i))如果(!长度(i)){flog.warn(“'我缺少”)na}别的如果(!是(i,'numeric“)){flog.info(”强制到数字“)as.numeric(i)} else {i}}
在参数中打开登录,并将阈值设置为WARN。
param < - snowparam(3,log = true,throupold =“warn”)bplapply(列表(1,“2”,Integer()),Fun,BPParam = Param)
降低信息和调试的阈值(即,使用bpthreshold < -
)查看如何在严重性上过滤消息。
对于长时间运行的作业或未经测试的代码,可以设置时间限制很有用。的超时字段是每个工人完成任务的时间,以秒为单位,以秒为单位允许。如果任务需要更长的时间超时工作者返回错误。
超时可以在参数施工期间设置,
Param < - SnowParam(Timeout = 20)Param
## class: SnowParam ## bpisup: FALSE;bpnworkers: 2;bptasks: 0;bpjobname: BPJOB ## bplog: FALSE;bpthreshold:信息;bpstopOnError: TRUE ## bptimeout: 20;bpprogressbar: FALSE ## bpRNGseed: ## bplogdir: NA ## bpresultdir: NA ## cluster type: SOCK
或者与setter:
Bptimeout (param) <- 2参数
## class: SnowParam ## bpisup: FALSE;bpnworkers: 2;bptasks: 0;bpjobname: BPJOB ## bplog: FALSE;bpthreshold:信息;BPStoponError:True ## Bptimout:2;bpprogressbar: FALSE ## bpRNGseed: ## bplogdir: NA ## bpresultdir: NA ## cluster type: SOCK
使用此函数在“x”值的数字向量上探索不同的_timeout_sbplapply ()
.'x'值小于超时那些人成功返回临界点返回一个错误。
fun <- function(i) {Sys.sleep(i) i}
分发文件超过工人:Genomicfiles :: DreambyFile()
使用之前的计数示例GenomicFiles :: DreambyByield()
它对单个文件进行操作,并实现了yield、map、reduce范式。在这个练习中,我们将使用Genomicfiles :: DreambyFile()
它使用bplaply()
在引擎盖下,并行地在多个文件上运行。
主要论点reduceByFile ()
是一组文件和一组范围。文件被发送到工作者,并根据范围提取数据子集。大部分工作是在办公室里完成的地图功能和可选减少函数组合每个worker的输出。
suppressPackageStartUpMessages({图书馆(生物竞争)库(GenomicFiles)库(基因组)库(RsamTools)})
在UNIX或Mac上,配置aMulticoreParam()
有4名工人。打开日志记录并设置60秒的超时。
param <- MulticoreParam(4, log = TRUE, timeout = 60)
在Windows上做同样的事情SnowParam()
:
Param < - SnowParam(4,log = true,超时= 60)
指向BAM文件的集合。
< /home/ubuntu/data/vobencha/LargeData/copynumber < /home/ubuntu/data/vobencha/LargeData/copynumber >bam$", full=TRUE) names(fls) <- basename(fls) bfl <- BamFileList(fls)
定义范围(兴趣区域)限制了工人上的数据量,并在控制下保留内存要求。我们将在染色体6上使用一组范围在主要的组织相容性复合物轨迹上。
范围< - Granges(“Chr6”,绞油(C(28477797,29527797,32448354),C(29477797,30527797,33448354)))
的地图功能在记录中读取并计数重叠。ReadGalignments()
对象中定义的范围的任何部分重叠的bam记录Scanbamparam.(即,它们可以重叠开始或结束)。一旦我们有记录R,我们希望只计算那些落在“范围内”的人。
地图< - 函数(范围,文件,......){库(基因组)## ReadGalignments(),ScanBamparam()Param = ScanBamparam(哪个=范围)##限制Gal = Readgalignments(文件,Param = Param)##日志消息flog.info(Paste0(“文件:”,baseName(文件)))flog.debug(Paste0(“记录:”,长度(gal)))##重叠OLAP < - footoverlaps(GAL,Range,Type =“在”中,icionore.strand = true)Tabulate(主题(OLAPS),主管长度(OLAP))}
数数 …
CTS < - DreambyByFile(范围,杂志,地图,BPParam = Param)
结果是列出与文件数相同的长度。
长度(CTS)
每个列表元素都是范围的长度。
ElementLengths(CTS)
每个范围的计数表用'[['[[':
cts ([1])
Lawrence,M和Morgan,M. 2014。具有R和Biocumon的可扩展基因组学。统计科学2014年,卷。29,2,214-226。http://arxiv.org/abs/1409.2864v1
生物共争:http://biocidodder.org/packages/release/bioc/html/biocparalles.html.html.
GenomicFiles:http://biocidodder.org/packages/release/bioc/html/genomicfiles.html.