原位作者:瓦莱丽·奥根特,马丁摩根
主持作者:Martin Morgan (martin.morgan@roswellpark.org)
日期:2016年7月15日
本节的目标是强调编写正确、健壮和高效的R代码的实践。
完全相同的()
,All.Equal()
)NA
价值观,......system.time ()
或者Microbenchmark.包中。Rprof ()
功能或包装函数lineprof或4月份矢量化 - 在向量上运行,而不是明确的循环
x <- 1 log(x) ## NOT for (i in 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
预先分配内存,然后填写结果
Result [i] <- runif(1): Result [i] <- runif(1) * Result [i - 1] Result
## [6] 0.9063429518 0.1066930705 0.086125086 0.0767101194 0.0599125034 ## [6] 0.0131052207 0.0060250919 0.0045694322 0.0008398694 0.0006845054
为了
循环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.088 0.091
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.116 0.000 0.114
头(预期)
## [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)
## f0(n) 93.75949 125.43283 120.7678 126.8942 127.3390 130.4134 5 ## f1(n) 97.80559 99.46675 116.5440 126.8709 129.2406 129.3359 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]
微基准测试(f0 (n), f2 (n),时间= 5)
## f2(n) 6.887973 6.981819 7.291664 7.08013 7.471796 8.03666 5 ## f0(n) 6.887973 6.981819 7.291664 7.08013 7.471796 8.03666
使用一个*应用()
函数,以避免必须显式地预分配,并使向量化的机会更加明显。
F3 < - 函数(n,a = 2)a * sapply(seq_len(n),log)相同(预期,f3(n))
# # [1]
Microbenchmark(F0(N),F2(N),F3(N),时间= 10)
## f0(n) 6.911975 7.036002 7.523884 7.272184 8.193247 8.391159 ## f3(n) 3.120228 3.167543 3.436611 3.281130 3.726726 4.354170 ## neval ## ## ## ## ## ## ## ## ## ##
现在代码显示在一行中,很明显它可以很容易地向量化。抓住机会将其矢量化:
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)的98247.257 100166.209 120943.9480 130044.098 130644.027 131510.762 ## F3(n)的2848.699 3077.010 3101.3840 3093.171 3190.727 3231.083 ## F4(N)204.107 206.843 294.2586 211.896 213.417 1034.029## Neval ## 10#10 ## 10
f4 ()
绝对似乎是胜利者。它如何扩展n
?(重复几次)
t <- sapply(N, function(i) system.time(f4(i))[[3]]) plot(t ~ N, log="xy", type="b")
对不同响应模式的解释?
得到教训:
*应用()
函数有助于避免显式预分配的需要,并使向量化的机会更加明显。这可能会以较小的性能成本为代价,但通常是值得的当数据太大而无法装入内存时,我们可以以块的形式遍历文件,或者按字段或基因组位置来划分数据子集。
迭代 - 块明智 -打开()
,阅读块(s),关闭()
。——例如,屈服
参数RSAMTOOLS :: BAMFILE()
- 框架:GenomicFiles: reduceByYield ()
限制—对感兴趣的列和/或行进行限制—利用特定于领域的格式—BAM文件和Rsamtools: ScanBamParam ()
- BAM文件和RSAMTOOLS :: PILPPALAM()
- VCF文件和VariantAnnotation :: scanvcfparam()
-使用数据库
迭代文件:`genomicfiles :: dreambybyyield()
suppressPackageStartupMessages({库(GenomicFiles)图书馆(GenomicAlignments)图书馆(Rsamtools)库(TxDb.Hsapiens.UCSC.hg19.knownGene)})收益率< - #如何输入的下一块数据函数(X,…){readGAlignments (X)} < - #如何映射到每个块功能(价值,…{olaps <- findoverlap (VALUE, roi, type="within", ignore.strand=TRUE) count <- tabulate(subjectHits(olaps), subjectLength(olaps)) setNames(count, names(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”“chabfile”## [7]“twobitfile”“fastafile”“tabseparatedfile”## [10]“compressurefile”“gff2file”“gff2file”## [13]“gff3file”“bedgraphfile”“bed15file”## [16]“bedpefile”“bwfile”“2bitfile”## [19]“gtffile”“gvffile”“gzfile”##[22]“bgzfile”“bz2file”“xzfile”
笔记
打开()
,关闭()
,进口()
/产量()
/读*()
.Bai.
bam指数);选择(“列”);限制(“行”)*文件列表()
班级
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)
## Error: BiocParallel errors ##元素索引:2 ##第一个错误:数学函数的非数字参数
还可以捕获错误和部分计算的结果
res <- bptry(bplapply(X, sqrt, BPPARAM=param)
## [[1]] ## [1] 1 ## ## [[2]] ## ## traceback()可用为'attr(x, "traceback")' ## ## [[3]] ## [1] 1.732051
通过重复呼叫重新运行失败的结果bplapply ()
这次通过校正的输入数据和部分结果为“BPREDO”。只重新运行失败的值。
X.redo <- list(1, 2, 3)/ /返回BPREDO = res)
##恢复以前的计算......
([1]) # # # # # # # # [1] 1 [[2]] 1.414214 # # # # # # [1] [[3]] # # 1.732051 [1]
或者,切换到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。
bplapply(list(1, "2", integer())), FUN, BPPARAM = param)
降低信息和调试的阈值(即,使用bpthreshold < -
)查看如何在严重性上过滤消息。
对于长时间运行的作业或未经测试的代码,可以设置时间限制很有用。的超时字段是每个工人完成任务的时间,以秒为单位,以秒为单位允许。如果任务需要更长的时间超时工作者返回错误。
超时可在参数构造时设置,
SnowParam <- SnowParam(timeout = 20
##类:SnowParam ## BPISUP:FALSE;BPWorkers:6;BPTASKS:0;bpjobname:bpjob ## bplog:false;BPThreshold:信息;BPStoponError:True ## Bptimout:20;bpprogressbar:false ## bprgseed:## bplogdir:na ## bpresultdir:na ##群集类型:袜子
或者与setter:
Bptimeout (param) <- 2参数
##类:SnowParam ## BPISUP:FALSE;BPWorkers:6;BPTASKS:0;bpjobname:bpjob ## bplog:false;BPThreshold:信息;BPStoponError:True ## Bptimout:2;bpprogressbar:false ## bprgseed:## bplogdir:na ## bpresultdir:na ##群集类型:袜子
使用此函数在“x”值的数字向量上探索不同的_timeout_sbplapply ()
。'x'值小于超时当那些结束时返回成功临界点返回一个错误。
fun <- function(i) {Sys.sleep(i) i}
在工人中分发文件:GenomicFiles: reduceByFile ()
使用之前的计数示例GenomicFiles: reduceByYield ()
它对单个文件进行操作,并实现了yield、map、reduce范式。在这个练习中,我们将使用GenomicFiles: reduceByFile ()
它使用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)
定义范围(感兴趣的区域)限制worker上的数据量,并保持对内存需求的控制。我们将使用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])
GoogleGenomics.与谷歌进行云计算和资源交互
Lawrence,M和Morgan,M. 2014。具有R和Biocumon的可扩展基因组学。统计科学2014年,卷。29,2,214-226。http://arxiv.org/abs/1409.2864v1
BiocParallel:http://biocidodder.org/packages/release/bioc/html/biocparalles.html.html.
GenomicFiles://www.andersvercelli.com/packages/release/bioc/html/GenomicFiles.html