在R中,For循环的速度是使用rpy2库的Python中的几倍
以下简单的在R中,For循环的速度是使用rpy2库的Python中的几倍,python,r,performance,rpy2,Python,R,Performance,Rpy2,以下简单的for块在R中完成大约需要3秒: library(MASS) nruns <- 2000 nelems <- 50 maxX <- 1 maxY <- 1 for(i in 1:nruns) { dataX <- runif(nelems, 0, maxX) dataY <- runif(nelems, 0, maxY) kde2d(dataX, dataY, n=50, lims=c(0, maxX, 0, maxY) )
for
块在R
中完成大约需要3秒:
library(MASS)
nruns <- 2000
nelems <- 50
maxX <- 1
maxY <- 1
for(i in 1:nruns) {
dataX <- runif(nelems, 0, maxX)
dataY <- runif(nelems, 0, maxY)
kde2d(dataX, dataY, n=50, lims=c(0, maxX, 0, maxY) )
}
这仅仅是因为我正在使用
rpy2
库与R
进行通信,还是有其他原因在起作用?这能以任何方式得到改进吗(同时仍然在Python中运行代码)?当然,连接到外部语言API会比直接运行外部语言慢。但是,请考虑将所有的东西保存在Python层中,避免<代码> r()>代码>调用。< /P>
from rpy2.robjects.packages import importr
base = importr("base")
stats = importr("stats")
mass = importr("MASS")
nruns = 2000
nelems = 50
maxX = 1
maxY = 1
for _ in range(nruns):
dataX = stats.runif(nelems, 0, maxX)
dataY = stats.runif(nelems, 0, maxY)
kde2dmap = mass.kde2d(dataX, dataY, n=50, lims=base.c(0, maxX, 0, maxY))
4到5倍的速度似乎有点慢,但如果您使用自定义转换,则可能会出现这种情况(rpy2可以动态地将R对象转换为任意Python对象-请参阅文档) 或者,您可能是在HPC上,对于安装Python和包的位置,NFS访问速度较慢,而R在更快的本地磁盘上(这可能会对启动时间产生很大影响) 否则,也可以将循环保持在R中,以评估这是否会改变运行时间:
from rpy2.robjects import r
from rpy2.robjects.packages import importr
# importr('MASS')
# Calling 'importr' will perform quite a bit of work behind the
# scene. That works allows a more intuitive/pythonic use of the
# content of the R library "MASS", but if you are just passing
# a string to be evaluated for R evaluation you can skip it
# replace it with the following:
r('library("MASS")')
nruns = 2000
r.assign('nelems', 50)
r.assign('maxX', 1)
r.assign('maxY', 1)
r.assign('nruns', nruns)
r("""
for(i in 1:nruns) {
dataX <- runif(nelems, 0, maxX)
dataY <- runif(nelems, 0, maxY)
kde2dmap <- kde2d(dataX, dataY, n=50, lims=c(0, maxX, 0, maxY) )
}
""")
关于性能的另一个评论是,rpy2从C扩展到
cffi
的转换导致了使用R的C API管理对话框的代码结构的显著改进(以及修复的一些棘手的错误),但在这里和那里的性能上有暂时的损失。速度优化正在逐步重新引入。我不知道你能做到这一点。这比完整的R
实现稍微慢一点。非常感谢。很高兴听到。没问题。如果不需要Python对象传递到R,请考虑调用<代码>子进程< /C>来直接运行R脚本。哇,这比PARFIT的答案快很多。他们的代码执行importr()
行大约需要6.5秒,执行循环大约需要7.5秒。你的答案需要大约4秒的时间。这是怎么回事?为什么这么快?(哦,谢谢!)在R中调用importr()
应该比调用library()
要花更多的时间。我在回答中添加了一个关于这一点的注释。当然,@Gabriel,因为lgautier是rpy2
。也许在未来的rpy2
版本中,R方法可以隐式转换作为参数发送的Python类型(int->IntVector,float->FloatVector)而且importr
可以简化包的映射?@Parfait:rpy2
已经能够自动将int
或float
类型的Python标量转换为R长度的一个向量。然而,在这个关于优化的示例中,maxX
,maxY
和nelems
在循环期间是恒定的。为所有迭代创建一次相应的R向量将节省一点额外的时间。回答得很好,非常感谢你们两位!
from rpy2.robjects import r
from rpy2.robjects.packages import importr
# importr('MASS')
# Calling 'importr' will perform quite a bit of work behind the
# scene. That works allows a more intuitive/pythonic use of the
# content of the R library "MASS", but if you are just passing
# a string to be evaluated for R evaluation you can skip it
# replace it with the following:
r('library("MASS")')
nruns = 2000
r.assign('nelems', 50)
r.assign('maxX', 1)
r.assign('maxY', 1)
r.assign('nruns', nruns)
r("""
for(i in 1:nruns) {
dataX <- runif(nelems, 0, maxX)
dataY <- runif(nelems, 0, maxY)
kde2dmap <- kde2d(dataX, dataY, n=50, lims=c(0, maxX, 0, maxY) )
}
""")
import rpy2.rinterface as ri
ri.initr()
ri.baseenv['library']("MASS")
# early bindings for R functions:
runif = ri.globalenv.find('runif')
kde2d = ri.globalenv.find('kde2d')
# create constant values in loop as R objects
maxX = ri.IntVector((1, ))
maxY = ri.IntVector((1, ))
nelems = ri.IntVector((50, ))
zero = ri.IntVector((0, ))
limits = ri.IntVector((0, maxX[0], 0, maxY[0]))
for i in range(nruns):
dataX = runif(nelems, zero, maxX)
dataY = runif(nelems, zero, maxY)
kde2dmap = kde2d(dataX, dataY, n=nelems, lims=limits)