我正在尝试扩展一个大型矩阵(我实际使用的矩阵要大得多):
x = matrix(rnorm(1e8), nrow=1e4)
x = scale(x)
这个矩阵使用了大约800 MB的内存。但是,使用lineprof,我看到scale函数分配了9.5 GB的内存,并在运行结束后释放了8.75 GB。由于这个函数的内存效率非常低,所以当我运行它时,它有时会使我的会话崩溃。
我试图找到一种内存效率高的方法来运行这个函数。如果我自己编写代码,它只分配了~6.8 GB,但这似乎仍然很多:
x = matrix(rnorm(1e8), nrow=1e4)
u = apply(x, 2, mean)
s = apply(x, 2, sd)
x = t((t(x) - u)/s)
我想我可以做得更好,把x的列分成组,然后分别缩放每个列组:
x = matrix(rnorm(1e8), nrow=1e4)
g = split(1:ncol(x), ceiling(1:ncol(x)/100))
for(j in g){
x[,j] = scale(x[,j])
}
使用profvis时,我发现这个函数总体上效率较低。它分配了10.8 GB内存,释放了10.5 GB。然而,我认为R可能可以在for循环中进行垃圾收集,但它没有这样做,因为它不需要这样做。这是正确的吗?如果是这样,那么这可能是最好的选择?
问题:
·编写这样的函数以避免内存崩溃的最佳方法是什么?(如果有可用的软件包,那就更好了)
·**在分析代码时如何考虑垃圾收集?**我的理解是,除非需要,否则GC不会一直运行。
更新:在运行时方面,将列分成10组并不比使用scale(x)函数慢多少。在[1000 x 1000]矩阵上运行这两个函数,使用微基准评估的平均运行时为:
·刻度(x)= 154毫秒
·拆分为10个色谱柱组= 167 ms
·拆分为1000个列组(即分别缩放每个列)= 373 ms
2条答案
按热度按时间toe950271#
假设你不需要保留原始矩阵,你可以直接修改它(而不是复制它)来保存一些内存。另外,你可以用一个简单的for循环来绕过base::scale。例如:
在我的机器中,只有这些微小的改变才能显著降低峰值内存(请在您想要的矩阵维度上测试)。
zi8p0yeb2#
根据
adn bps
关于内存使用的评论修改我的答案。首先我使用gc{base}
垃圾收集函数来释放一些内存。我发现了一个我认为可以帮助你的表单,首先我用Rcpp包生成rnorm的矩阵,使用c++代码,它稍微加快了这个过程
矩阵
x
和y
的大小相同我加载库
data.table
,,并将矩阵x转换为data.table类,以使用scale函数现在,我使用bigmemory库来高效地使用内存,并且如果需要,我会删除原始矩阵x,以免在环境中累积大量对象
运行时间显示时间显著缩短,大约快了5倍。请注意,bigmatrix对象小了1百万倍。您可以重现一个简短示例,以查看matrix和bib.matrix中的scale结果相等