R语言中的代码运算性能提升

时间与空间的权衡,为了让程序更快运行可能需要更多的内存空间,另一方面为节省内存或许需编写运行速度稍慢的代码。一个R会话中的所有对象都保存在内存中,即R的内存地址空间中,R语言已可以支持2^31字节以上的向量

1.通过向量化的方式优化R代码

2.使用字节码编译

3.将R代码中最消耗CPU的部分用编译型语言编码,如C/C++

4.将R代码用并行方式编写

5.其他的一些方法

1.循环很慢

在有循环的代码中,涉及到大量的函数调用。如for()是一个函数、:是一个函数(置换函数)、向量取下标的操作是一个函数调用等等

调用函数是非常耗时的,因为其中牵扯到创建堆栈帧等过程,如果在循环的每次迭代中都有这些时间损耗,那么加起来会很耗时

2.向量化运算

有可能加速代码运算的向量化函数:ifelse\which\where\any\all\cumsum\

cumprod,对矩阵而言有rowSums\colSums

#向量化运算有时虽然获得了速度上的提升,但使用了更多内存
nreps=100000
xymat=matrix(rnorm(2*nreps),ncol=2)
maxs=pmax(xymat[,1],xymat[,2])	#向量化计算
print(mean(maxs))

生成幂次矩阵中的向量化思考

power1=function(x,dg){
	pw=matrix(x,nrow=length(x))
	prod=x
	for (i in 1:dg){
		prod=prod*i
		pw=cbind(pw,prod)	#逐列生成最终矩阵,但在内存分配上需要消耗更多时间
	}
	return(pw)
}

#在最开始即定义完整矩阵,分配内存
power2=function(x,dg){
	pw=matrix(nrow=length(x),ncol=dg)
	prod=x
	for (i in 1:dg){
		prod=prod*i
		pw[,i]=prod
	}
	return(pw)
}

#使用outer函数,运算时间反而更长
power3=function(x,dg){
return(outer(x,1:dg,"^"))	#FUN="^"并没有进行向量化
}

与运算性能有关的问题很多时候是不可预测的,要尽量尝试各种不同的方法

3.函数式编程与内存

1.向量赋值

z=c(1,2,3)
z[3]=4	#等价于z="[<-"(z,3,value=4)

上面代码中表面上只改变向量中的一个元素,但整个语句的含义是向量被重新计算了,这对于很长的向量会极大降低程序运行速度,而较短向量在循环中被反复赋值也会造成整体运行速度降低

2.改变时拷贝

x=c(1,2,3)
y=x
tracemem(x)	#报告变量的内存再分配情况<0000000005E6BF60>
tracemem(y)	#<0000000005E6BF60>

此时x与y共享相同的内存区域,当y发生改变时(x不变化),y对应的内存地址也会变化

y=2
tracemem(y)	#<0000000004CC9928>
x[2]=3
tracemem(x)	#<0000000004279FA0>,需要注意内存地址的变化

4.利用Rprof()寻找代码瓶颈

Rprof(filename = "Rprof.out", append = FALSE, interval = 0.02,
       memory.profiling = FALSE, gc.profiling = FALSE, 
       line.profiling = FALSE, numfiles = 100L, bufsize = 10000L)

Rprof()可提供一份报告,报告代码中调用的每个函数所消耗的时间(仅作为调优的参考使用)。Rprof每隔0.02秒(默认)R会检查一次函数调用栈并以此决定当前有用的函数,并将结果写入文件Rprof.out

sample.interval=20000
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"*" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
"cbind" "power1" 
#power1调用cbind,第一列是当前正在执行的函数,summaryRprof()可汇总这个文件的所有行

Rprof()函数用法

power1=function(x,dg){
	pw=matrix(x,nrow=length(x))
	prod=x
	for (i in 1:dg){
		prod=prod*i
		pw=cbind(pw,prod)	#逐列生成最终矩阵,但在内存分配上需要消耗更多时间
	}
	return(pw)
}

Rprof()	#开启监视器
x=rnorm(100000)
power1(x,40)	#invisible(power1(x,40))不显示运行过程
Rprof(NULL)	#NULL参数表示结束监视
summaryRprof()	#查看结果,从中可看到代码主要的运行时间花在哪个函数上

5.字节码编译

可利用字节码编译器尝试加速代码,但一般没有向量化的代码快,但字节码编译具有一定的提速潜力

library(compiler)
power1_com=cmpfun(power1)	#创建新函数-编译版本
system.time(power1_com(x,40))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值