写入函数中的大型矩阵 - 快速与慢速

时间:2011-11-17 15:02:04

标签: r matrix

[回复后的问题]

感谢您的回复。在我的问题中我不清楚,为此我道歉。

我会尝试提供更多有关我们情况的细节。我们有c。我们保存在环境中的100个矩阵。每个都非常大。如果可能的话,我们想要在执行更新时避免复制这些矩阵。我们经常遇到2GB内存限制,所以这对我们来说非常重要。

所以我们的两个要求是1)避免副本和2)通过名称间接寻址矩阵。速度虽然重要,但却是一个可以通过避免复制来解决的副问题。

在我看来,Tommy的解决方案涉及创建一个副本(虽然它完全回答了我的实际原始问题,所以我是那个有问题的人。)

下面的代码对我们来说是最明显的,但它清楚地创建了一个副本(如memory.size增加所示)

myenv <- new.env()
myenv$testmat1 <- matrix(1.0, nrow=6000, ncol=200)

testfnDirect <- function(paramEnv) {
    print(memory.size())

    for (i in 1:300) {
        temp <- paramEnv$testmat1[10,] 
        paramEnv$testmat1[10,] <- temp * 0
    }   
    print(memory.size())
}
system.time(testfnDirect(myenv))

使用 with 关键字似乎可以避免这种情况,如下所示:

myenv <- new.env()
myenv$testmat1 <- matrix(1.0, nrow=6000, ncol=200)

testfnDirect <- function(paramEnv) {
    print(gc())
    varname <- "testmat1" # unused, but see text
    with (paramEnv, {
        for (i in 1:300) {
            temp <- testmat1[10,] 
            testmat1[10,] <- temp * 0
        }
    })
    print(gc())
}
system.time(testfnDirect(myenv))

但是,该代码的工作原理是直接按名称寻址testmat1。我们的问题是我们需要间接解决它(我们事先不知道我们将更新哪些矩阵)。

有没有办法修改testfnDirect,以便我们使用变量varname而不是硬编码testmat

2 个答案:

答案 0 :(得分:2)

对'data.table'包的最近更改是专门为了避免在修改值时进行复制。因此,如果您的应用程序可以处理其他操作的data.tables,那么这可能是一个解决方案。 (它会很快。)

答案 1 :(得分:1)

嗯,如果你能解释为什么第一个解决方案不行,那就太好了......看起来更整洁,跑得更快。

尝试回答问题:

  1. foo[bar][baz] <- 42这样的“嵌套替换”操作非常复杂,并且针对某些情况进行了优化以避免复制。但很可能您的特定用例未经过优化。这将导致大量复制和性能损失。

    测试该理论的一种方法是在测试之前调用gcinfo(TRUE)。然后你会看到第一个解决方案触发2个垃圾收集,第二个解决方案触发160个左右!

  2. 这是您的第二个解决方案的变体,它将环境转换为列表,执行其操作并将转换回环境。它与您的第一个解决方案一样快。

  3. 代码:

    testfnList <- function() {
        mylist <- as.list(myenv, all.names=TRUE)
    
        thisvar <- "testmat2"
        for (i in 1:300) {
            temp <- mylist[[thisvar]][10,]
            mylist[[thisvar]][10,] <- temp * 0
        }
    
        myenv <<- as.environment(mylist)
    }
    system.time(testfnList()) # 0.02 secs
    

    ...如果你将myenv作为参数传递给函数,那当然会更整洁。 一个小的改进(如果你循环很多,而不仅仅是300次)将是按数字而不是名称索引(不适用于环境,但适用于列表)。只需更改thisvar

    thisvar <- match("testmat2", names(mylist))