Запись в большие матрицы внутри функции - быстро против медленно - PullRequest
4 голосов
/ 17 ноября 2011

[Вопрос исправлен после ответов]

Спасибо за ответы.Мне было неясно в моем вопросе, за который я прошу прощения.

Я постараюсь дать более подробную информацию о нашей ситуации.У нас есть с.100 матриц, которые мы храним в окружающей среде.Каждый очень большой.Если это вообще возможно, мы хотим избежать копирования этих матриц при выполнении обновлений.Мы часто сталкиваемся с ограничением в 2 ГБ памяти, так что это очень важно для нас.

Итак, два наших требования: 1) избегать копий и 2) косвенно обращаться к матрицам по имени.Скорость, хотя и важна, но является побочной проблемой, которую можно решить, избегая копирования.

Мне кажется, что решение Томми заключалось в создании копии (хотя она полностью отвечала на мой настоящий вопрос, поэтому я 'm тот, кто виноват).

Приведенный ниже код является наиболее очевидным для нас, но он явно создает копию (как показано увеличением 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))

Использованиеключевое слово с , по-видимому, этого избегает, как показано ниже:

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, а не hardcoding testmat

Ответы [ 2 ]

2 голосов
/ 18 ноября 2011

Довольно недавнее изменение в пакете 'data.table' было сделано специально для того, чтобы избежать копирования при изменении значений. Так что, если ваше приложение может обрабатывать data.tables для других операций, это может быть решением. (И это было бы быстро.)

1 голос
/ 17 ноября 2011

Хорошо, было бы неплохо, если бы вы могли объяснить, почему первое решение не в порядке ... Оно выглядит намного аккуратнее и работает быстрее.

Чтобы попытаться ответить на вопросы:

  1. Операция «вложенной замены», такая как foo[bar][baz] <- 42, очень сложна и оптимизирована для определенных случаев, чтобы избежать копирования. Но очень вероятно, что ваш конкретный вариант использования не оптимизирован. Это приведет к большому количеству копий и потере производительности.

    Способ проверить эту теорию - позвонить gcinfo(TRUE) перед вашими тестами. Затем вы увидите, что первое решение вызывает 2 сборки мусора, а второе - около 160!

  2. Вот вариант вашего второго решения, которое преобразует среду в список, выполняет свою работу и конвертирует обратно в среду. Это так же быстро, как ваше первое решение.

Код:

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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...