2 回答

TA貢獻1783條經驗 獲得超4個贊
慢 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) )
}
""")
速度改進將來自以下方面:
您問題中的代碼在每次迭代中傳遞 Python 字符串。每次在評估該字符串之前都必須(通過 R)對其進行解析。這可能會增加一些長循環的開銷。在我提供的代碼中,解析只執行一次。
importr()@Parfait 答案中的代碼利用了為要使用的 R 函數創建 Python 對象代理這一事實。但是,在創建映射時(為 R 包中的所有importr()對象創建映射)以及從 Python 到 R 的每次迭代(對象檢查和轉換、構建要評估的 R 表達式)時,仍然存在開銷。對代碼進行概要分析可以讓您準確了解時間花在了哪里。有一些方法可以在保留更多性能的同時保留一些 pythonic 方面。例如:
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)
關于性能的另一個評論是,rpy2 從 C 擴展到的過渡cffi導致使用 R 的 C API 管理對話的代碼結構有了顯著改進(并修復了許多棘手的錯誤),但代價是暫時的在這里和那里的表現。正在逐步重新引入速度優化。

TA貢獻1839條經驗 獲得超15個贊
自然地,連接到外部語言 API 比直接運行外部語言要慢。但是,請考慮將所有內容都保留在 Python 層中并避免r()調用。
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))
添加回答
舉報