Python Rpy R数据处理优化
我正在用Python和R写一个数据处理程序,并通过Rpy2进行连接。
输入的数据是二进制格式,我用Python读取这些数据,然后把它们传给R,最后再把结果收集出来输出。
数据被分成小块,每块大约100字节(每个值1字节,共100个值)。
现在程序可以运行,但速度非常慢。以下是我对1GB大小(也就是10^7块数据)的测试结果:
如果我禁用Rpy2的调用进行干跑,Python在一个3.06GHz的Intel(R) Xeon(TM) CPU上用单线程循环处理所有数据大约需要90分钟。
如果我启用完整功能和多线程,那么在这个双核的Xeon上,程序估计需要大约200小时才能完成。
我多次终止了Python程序,因为调用栈几乎总是指向Rpy2的函数接口。我还进行了性能分析,结果也差不多。
所有这些观察结果表明,R部分通过Rpy2调用是瓶颈。因此,我对我的R程序的独立版本进行了性能分析,但分析总结指向了“匿名”。我仍在努力找出我的R脚本中最耗时的部分。****更新,见我下面的编辑*****
不过,有两个可疑的地方,一个是使用wmtsa包进行的连续小波变换(CWT)和小波变换模极大值(WTMM),另一个是对ex-gaussian曲线的非线性拟合。
我想到的有:
对于拟合,我可以用内联C代码替代R的函数吗?C和Fortran中有很多拟合库可用……(这个想法来自网络;我从没做过;不确定)
对于小波算法……我需要分析wmtsa包,重写热点部分为C代码吗?……用C或Fortran重新实现整个wmtsa包对我来说会非常复杂。我没有太多编程经验。
文件中的数据块是以20个连续字节组织的,我可以直接映射到一个类似C的char*数组吗?目前我的Python程序是每次读取一个字节并将其添加到列表中,这样速度很慢。这部分代码需要1.5小时,而R需要大约200小时,所以这不是那么紧急。
这是我第一次在解决实际问题时遇到程序效率的问题。我在网上搜索了一下,感觉信息量很大,有点不知所措。请给我一些建议,告诉我接下来该怎么做。
谢谢!
脚注:
* 更新 *
感谢cran的proftools,我成功创建了一个调用栈图。我发现大约56%的时间花在了wmtsa上,代码片段如下:
W <- wavCWT(s,wavelet="gaussian1",variance=1/p) # 1/4
W.tree <-wavCWTTree(W) # 1/2
holderSpectrum(W.tree) # 1/4
大约28%的时间花在了nls上:
nls(y ~ Q * dexGAUS(x, m, abs(s), abs(n)) + B, start = list(Q = 1000, m = h$time[i], s = 3, n = 8, B = 0), algorithm="default", trace=FALSE)
其中gamlss.dist包中的dexGAUS评估占用了大部分时间。
剩下的约10%的R时间花在数据传递/拆分/聚合/子集上。
2 个回答
对于选项3... 高效地获取数据... 在Python中,可以通过一次性从文件中读取,将所有数据作为一个长字符串来处理。我们假设这个字符串叫做myStr。
import array
myNums = array.array('B', myStr)
现在,myNums是一个数组,里面存放着每个字节,转换起来很简单... 你可以查看一下help(array.array)... 实际上,从文件中直接通过数组获取数据也是可以的。
这样做应该能节省你1.4小时的数据读取时间。
我的理解是你遇到了以下问题:
你有一些 Python 代码,其中用到了 rpy2。
你发现性能问题,这些问题和调用 rpy2 有关。
不过,这些性能问题似乎和 rpy2 本身关系不大,因为主要的运行时间是由底层的 R 代码造成的。
你的一部分 R 代码是逐个读取字节并把它们添加到一个列表中,你通过把这部分代码移到 Python 中来改善了性能。
在没有看到实际代码的情况下,帮助你有点困难,你可以考虑以下几点:
使用缓冲策略来读取字节(这已经有人回答过了)。
优化你的 R 代码。
考虑简单的并行处理(最终可以在云上租用计算空间)。