R︱foreach+doParallel并行+联用迭代器优化内存+并行机器学习算法
要学的东西太多,无笔记不能学~~ 欢迎关注公众号,一起分享学习笔记,记录每一颗“贝壳”~
———————————————————————————
接着之前写的并行算法parallel包,parallel相比foreach来说,相当于是foreach的进阶版,好多东西封装了。而foreach包更为基础,而且可自定义的内容很多,而且实用性比较强,可以简单的用,也可以用得很复杂。笔者将自己的学习笔记记录一下。
R︱并行计算以及提高运算效率的方式(parallel包、clusterExport函数、SupR包简介)
——————————————————————————————————————
一、foreach包简介与主要函数解读
foreach包是revolutionanalytics公司贡献给R开源社区的一个包,它能使R中的并行计算更为方便。大多数并行计算都主要完成三件事情:将问题分割小块、对小块问题进行并行计算、合并计算结果。foreach包中,迭代器完成分割工作,”%dopar%“函数实现对小块的并行计算,”.combine”函数完成合并工作。
foreach(..., .combine, .init, .final=NULL, .inorder=TRUE,
.multicombine=FALSE,
.maxcombine=if (.multicombine) 100 else 2,
.errorhandling=c('stop', 'remove', 'pass'),
.packages=NULL, .export=NULL, .noexport=NULL,
.verbose=FALSE)
when(cond)
e1 %:% e2
obj %do% ex
obj %dopar% ex
times(n)
参数解读:
(1)%do%严格按照顺序执行任务(所以,也就非并行计算),%dopar%并行执行任务,%do%时候就像sapply或lapply,%dopar%就是并行启动器
(2).combine:运算之后结果的显示方式,default是list,“c”返回vector, cbind和rbind返回矩阵,"+"和"*"可以返回rbind之后的“+”或者“*”,帮你把数据整合起来,太良心了!!
(3).init:.combine函数的第一个变量
(4).final:返回最后结果
(5).inorder:TRUE则返回和原始输入相同顺序的结果(对结果的顺序要求严格的时候),FALSE返回没有顺序的结果(可以提高运算效率)。这个参数适合于设定对结果顺序没有需求的情况。
(6).muticombine:设定.combine函数的传递参数,default是FALSE表示其参数是2,TRUE可以设定多个参数
(7).maxcombine:设定.combine的最大参数
(8).errorhandling:如果循环中出现错误,对错误的处理方法
(9).packages:指定在%dopar%运算过程中依赖的package(%do%会忽略这个选项),用于并行一些机器学习算法。
(10).export:在编译函数的时候需要预先加载一些内容进去,类似parallel的clusterExport
如果你不知道自己的机器有没有启动并行,你可以通过以下的函数来进行查看,帮助你理解自己电脑的核心数:
getDoParWorkers( ) #查看注册了多少个核,配合doMC package中的registerDoMC( )使用 getDoParRegistered( ) # 查看doPar是否注册;如果没有注册返回FALSE getDoParName( ) #查看已经注册的doPar的名字 getDoParVersion( ) #查看已经注册的doPar的version
本节内容主要参考:R语言处理大数据
——————————————————————————————————————
二、新手教程:foreach应用
1、最简单模式——堪比lapply
foreach(a=1:3, b=rep(10, 3)) %do% {
a + b
}
## [[1]]
## [1] 11
##
## [[2]]
## [1] 12
##
## [[3]]
## [1] 13
这个并不是并行,只是有着类似lapply的功能。
foreach返回的是list格式值,list格式是默认的数据格式。来看看上面的内容怎么用lapply实现:
lapply(cbind(1:3,rep(10,3),function(x,y) x+y ))
但是有个小细节就是,%do%之后的{}可以随意写中间赋值过程,譬如c<-a+b,这个用lapply不是特别好写。所以这个我超级喜欢!
这里需要注意的一点是:a, b叫循环变量,循环次数取两者长度中最小的。譬如a=1,2,3 b=1,2,也就只能循环两次。
2、参数:.combine——定义输出结果的整合
默认是foreach之后返回的是list,你可以指定自己想要的格式。.combine选项连接了“c”函数,该函数的功能是连接所有返回值组成向量。此外,我们可以使用“cbind”将生成的多个向量组合成矩阵,例如生成四组随机数向量,进而按列合并成矩阵:
foreach(i=1:4, .combine="cbind") %do% rnorm(4) ## result.1 result.2 result.3 result.4 ## [1,] 0.26634 -0.73193 -0.25927 0.8632 ## [2,] 0.54132 0.08586 1.46398 -0.6995 ## [3,] -0.15619 0.85427 -0.47997 0.2160 ## [4,] 0.02697 -1.40507 -0.06972 0.2252
运算之后结果的显示方式,default是list,“c”返回vector, cbind和rbind返回矩阵,"+"和"*"可以返回rbind之后的“+”或者“*”,帮你把数据整合起来。
.combine还可以接上自己编译的函数,这点很人性化,譬如:
cfun <- function(a, b) a+b foreach(i=1:4, .combine="cfun") %do% rnorm(4)
.combine帮你把输出结果,再要调整的问题一次性解决了,并且将数据整合也进行并行加速,棒!
一些关于.combine的c,rbind,cbind,*,+其他案例:
x <- foreach(a=1:3, b=rep(10, 3), .combine="c") %do%
{
x1<-(a + b);
x2<-a*b;
c(x1,x2);
}
> x
[1] 11 10 12 20 13 30
> x <- foreach(a=1:3, b=rep(10, 3), .combine="rbind") %do%
{
x1<-(a + b);
x2<-a*b;
c(x1,x2);
}
> x
[,1] [,2]
result.1 11 10
result.2 12 20
result.3 13 30
> x <- foreach(a=1:3, b=rep(10, 3), .combine="cbind") %do%
{
x1<-(a + b);
x2<-a*b;
c(x1,x2);
}
> x
result.1 result.2 result.3
[1,] 11 12 13
[2,] 10 20 30
> x <- foreach(a=1:3, b=rep(10, 3), .combine="+") %do%
{
x1<-(a + b);
x2<-a*b;
c(x1,x2);
}
> x
[1] 36 60
> x <- foreach(a=1:3, b=rep(10, 3), .combine="*") %do%
{
x1<-(a + b);
x2<-a*b;
c(x1,x2);
}
> x
[1] 1716 6000
3、参数.inorder——定义输出结果的顺序
.inorder:TRUE则返回和原始输入相同顺序的结果(对结果的顺序要求严格的时候),FALSE返回没有顺序的结果(可以提高运算效率)。这个参数适合于设定对结果顺序没有需求的情况。
顺序这东西,写过稍微复杂的函数都知道,特别在数据匹配时尤为重要,因为你需要定义一些rownames的名称,这时候输出的顺序万一不匹配,可能后面还要花时间匹配过来。
foreach(i=4:1, .combine='c', .inorder=FALSE) %dopar% {
Sys.sleep(3 * i)
i
}
## [1] 4 3 2 1
——————————————————————————————————————
三、中级教程:利用doParallel并行+联用迭代器优化内存
1、利用doParallel并行——%dopar%
foreach包创作是为了解决一些并行计算问题,将”%do%“更改为“%dopar%”前面例子就可以实现并行计算。在并行之前,需要register注册集群:
library(foreach) library(doParallel) cl<-makeCluster(no_cores) registerDoParallel(cl)
要记得最后要结束集群(不是用stopCluster()):stopImplicitCluster()
2、参数when——按条件运算
foreach(a=irnorm(1, count=10), .combine='c') %:% when(a >= 0) %do% sqrt(a)
其中when是通过%:%来导出,而且%:%之后,还可以接%do%
qsort <- function(x) {
n <- length(x)
if (n == 0) {
x
} else {
p <- sample(n, 1)
smaller <- foreach(y=x[-p], .combine=c) %:% when(y <= x[p]) %do% y
larger <- foreach(y=x[-p], .combine=c) %:% when(y > x[p]) %do% y
c(qsort(smaller), x[p], qsort(larger))
}
}
qsort(runif(12))
## [1] 0.1481 0.2000 0.2769 0.4729 0.4747 0.5730 0.6394 0.6524 0.8315 0.8325
## [11] 0.8413 0.8724
3、联用iterators——优化、控制内存
iter(obj, by=c('column', 'cell', 'row'), chunksize=1L, checkFunc=function(...) TRUE, recycle=FALSE, ...)
参数解读:
(1)iter+function迭代输出
来看一个iter案例,帮你把函数分块给你,不用一次性导入计算,耗费内存:
> a
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
> i2 <- iter(a, by = "column", checkFunc=function(x) sum(x) > 50)
> nextElem(i2)
[,1]
[1,] 13
[2,] 14
[3,] 15
[4,] 16
> nextElem(i2)
[,1]
[1,] 17
[2,] 18
[3,] 19
[4,] 20
> nextElem(i2)
错误: StopIteration
不过,如果没有next了,就会出现报错,这时候就需要稍微注意一下。
(2)生成随机数
> i2 <- icountn(c(3.4, 1.2)) > nextElem(i2) [1] 1 1 > nextElem(i2) [1] 2 1 > nextElem(i2) [1] 3 1 > nextElem(i2) [1] 4 1 > nextElem(i2) [1] 1 2 > nextElem(i2) [1] 2 2 > nextElem(i2) [1] 3 2 > nextElem(i2) [1] 4 2 > nextElem(i2) 错误: StopIteration
——————————————————————————————————————
四、高级教程:并行机器学习算法
并行计算一些小任务会比按顺序运算它们花费更多的时间,所以当普通运算足够快的时候,并没有必要使用并行计算模式改进其运算效率。
同时,最适合并行莫过于随机森林算法了。
#生成矩阵x作为输入值,y作为目标因子 x <- matrix(runif(500), 100) y <- gl(2, 50) #导入randomForest包 require(randomForest)
1、独立循环运行随机森林算法
如果我们要创建一个包含1200棵树的随机森林模型,在6核CPU电脑上,我们可以将其分割为六块执行randomForest函数六次,同时将ntree参赛设为200,最后再将结果合并。
rf <- foreach(ntree=rep(200, 6), .combine=combine) %do% randomForest(x, y, ntree=ntree) rf ## ## Call: ## randomForest(x = x, y = y, ntree = ntree) ## Type of random forest: classification ## Number of trees: 1200 ## No. of variables tried at each split: 2
分开来运行6个200树的随机森林算法。
2、参数.packages——并行运行随机森林算法
将%do%改为“%dopar%”,同时使用.packages调用randomForest:
rf <- foreach(ntree=rep(200,6), .combine=combine, .packages="randomForest") %dopar% randomForest(x, y, ntree=ntree) rf
通过.packages来将函数包导入其中,类似parallel中的clusterEvalQ,但是foreach在一个函数里面包含了函数、包的导入过程。
当然还可以使用一些其他包,使用.packages参数来加载包,比如说:.packages = c("rms", "mice")
3、参数.export——将doParallel并行写入函数
test <- function (exponent) {
foreach(exponent = 2:4,
.combine = c) %dopar%
base^exponent
}
test()
Error in base^exponent : task 1 failed - "object 'base' not found"
base <- 2
cl<-makeCluster(2)
registerDoParallel(cl)
base <- 4
test <- function (exponent) {
foreach(exponent = 2:4,
.combine = c,
.export = "base") %dopar%
base^exponent
}
test()
stopCluster(cl)
[1] 4 8 16
——————————————————————————————————————
应用一:并行时.dopar,如何输入多个常规值,.export输入多个值?
本节想解决的问题:
1、能不能输出每次迭代的时间?(参考:R语言︱函数使用技巧(循环、if族/for、switch、repeat、ifelse、stopifnot))
2、并行的时候,如何导入多个数值型变量?
注意:
.export需要输入方程中没有的值,而且必须是一个文本型,可以用list的方式。
library(foreach)
registerDoParallel(makeCluster(2))
a=c(1,2,3)
b=c(3,4,5,5,5,5)
d=c(2,4,35,5,5,2)
i=0
t1 = Sys.time()
foreach(x=a, .combine="rbind",.export="list(b,d,i,t1)") %dopar% {
cc=b+d
a+cc
i=i+1
print(paste("迭代了",i,"次",sep=""))
print(difftime(Sys.time(), t1, units = 'sec'))
}
注意代码中,设置了2个核心。
.combine可以将数据合并起来,之后步骤在所有结果出来之后再进行相应的合并。所以结果出来,会有result.1等项目:
[1] "迭代了1次"
Time difference of 0.03000283 secs
[1] "迭代了2次"
Time difference of 0.031003 secs
[1] "迭代了3次"
Time difference of 0.031003 secs
[,1]
result.1 0.03000283
result.2 0.03100300
result.3 0.03100300
——————————————————————————————————————
参考文献:
1、R语言中的并行计算:foreach,iterators, doParallel包
2、foreach包简介 / FROM:《Using The foreach Package》
4、R︱并行计算以及提高运算效率的方式(parallel包、clusterExport函数、SupR包简介)
R︱foreach+doParallel并行+联用迭代器优化内存+并行机器学习算法的更多相关文章
- 【R】如何确定最适合数据集的机器学习算法 - 雪晴数据网
[R]如何确定最适合数据集的机器学习算法 [R]如何确定最适合数据集的机器学习算法 抽查(Spot checking)机器学习算法是指如何找出最适合于给定数据集的算法模型.本文中我将介绍八 ...
- Android性能优化之巧用软引用与弱引用优化内存使用
前言: 从事Android开发的同学都知道移动设备的内存使用是非常敏感的话题,今天我们来看下如何使用软引用与弱引用来优化内存使用.下面来理解几个概念. 1.StrongReference(强引用) 强 ...
- OpenMP共享内存并行编程详解
实验平台:win7, VS2010 1. 介绍 平行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个CPU,它们都有 ...
- C++ Primer 学习笔记_98_特殊的工具和技术 --优化内存分配
特殊的工具和技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自己主动执行合适的构造函数来初始化每一个动态 ...
- Java进阶7 并发优化2 并行程序设计模式
Java进阶7 并发优化2 并行程序设计模式20131114 1.Master-worker模式 前面讲解了Future模式,并且使用了简单的FutureTask来实现并发中的Future模式.下面介 ...
- 社交网络分析的 R 基础:(四)循环与并行
前三章中列出的大多数示例代码都很短,并没有涉及到复杂的操作.从本章开始将会把前面介绍的数据结构组合起来,构成真正的程序.大部分程序是由条件语句和循环语句控制,R 语言中的条件语句(if-else)和 ...
- cocos2d 如何优化内存使用
如何优化内存使用 内存优化原理 为优化应用内存使用,开发人员首先应该知道什么最耗应用内存,答案就是纹理! 纹理几乎会占据90%应用内存.所以尽量最小化应用的纹理内存使用,否则应用很有可能会因为低内存而 ...
- cocos2d-x如何优化内存的应用
自身以前也写过cocos2d-x如何优化内存的应用,以及内存不够的情况下怎么样处置惩罚游戏.今天在微博中看到有友好简介了下内存,挺详细的.不晓得是谁写的,我纪录下. 一,IOS与图片内存 在IOS上, ...
- Redis 小白指南(三)- 事务、过期、消息通知、管道和优化内存空间
Redis 小白指南(三)- 事务.过期.消息通知.管道和优化内存空间 简介 <Redis 小白指南(一)- 简介.安装.GUI 和 C# 驱动介绍> 讲的是 Redis 的介绍,以及如何 ...
随机推荐
- 几次面试后才弄懂的HashMap
本人大四,以前也开发过几个项目,Map相关集合也总用.但是从来没有研究过底层的实现,只知道杂用.结果在最开始的几次面试中一脸懵逼.认识到不足后,浅显的学习了一下,总结成一下几点.(如果写错了还望指正) ...
- C语言打印不出百分号'%'(以解决)
1. 问题描述 今天,我需要把百分号'%'打印出来,考虑到它是特殊符号,我就用转义字符'\',和它组合,结果是漆黑的屏幕什么也没有. 2. 解决办法 我问度娘, 她告诉我要打印百分号需要在它的前 ...
- echarts中视觉映射器(visualMap)与时间轴(timeline)混用的实现方法
1.简述 echarts中的 timeline 组件,提供了在多个 ECharts option 间进行切换.播放等操作的功能. 与其他组件些不同,它需要操作『多个option』. 所以除了基准的ba ...
- SpringBoot与Mybatis整合方式01(源码分析)
前言:入职新公司,SpringBoot和Mybatis都被封装了一次,光用而不知道原理实在受不了,于是开始恶补源码,由于刚开始比较浅,存属娱乐,大神勿喷. 就如网上的流传的SpringBoot与Myb ...
- 不使用Math.random实现随机数
不使用Math.random实现随机数 var rand = (function(){ var today = new Date(); var seed = today.getTime(); func ...
- PLSQL Developer软件使用大全
PLSQL Developer软件使用大全 第一章 PLSQL Developer特性 PL/SQL Developer是一个集成开发环境,专门面向Oracle数据库存储程序单元的开发.如今,有越来越 ...
- Py3编码解码
Py3编码解码 写的不好请谅解,有问题欢迎指出. python2.x中的解决方案(图片来源于网络) #!/usr/bin/env python # -*- coding: utf-8 -*- ...
- BZOJ 3545: [ONTAK2010]Peaks [Splay启发式合并]
3545: [ONTAK2010]Peaks 题意:带权图,多组询问与一个点通过边权\(\le x\)的边连通的点中点权k大值 又读错题了,输出点一直WA,问的是点权啊 本题加强版强制在线了,那这道题 ...
- BZOJ 3569: DZY Loves Chinese II [高斯消元XOR 神题]
http://www.lydsy.com/JudgeOnline/problem.php?id=3569 题意:多次询问一个无向连通图当图中某k条边消失时这个图是否联通 强制在线 太神啦啦啦啦啦啦啦啦 ...
- xBIM WeXplorer xViewer 浏览器检查
目录 基础 xBIM WeXplorer 简要介绍 xBIM WeXplorer xViewer 基本应用 xBIM WeXplorer xViewer 浏览器检查 xBIM WeXplorer xV ...