Проблема
Я хочу написать функцию, которая изменяет каждый столбец большой матрицы Икс:
f = function(x){
# do something to x
# return x
}
Поскольку Икс очень большой, я хотел бы изменить его «на месте», то есть без создания копии. Однако я понимаю, что в R функции «копируются при изменении». Другими словами, если я изменю Икс в функции ж, R сделает копию Икс.
Предлагаемое решение (Обновление: не работает! См. Ответы ниже для подробностей.)
Поэтому кажется, что лучшим решением является изменение глобальной переменной, т.е.
f = function(x){
x = deparse(substitute(x))
x = get(x, envir = globalenv())
# do something to x
}
Вопрос
Однако люди в SO ОЧЕНЬ отрицательно относятся к передаче глобальных переменных в функции в R. Некоторых людей даже отвергали просто за то, что они спрашивали об этом.
У меня вопрос: как лучше всего сделать что-то подобное в R?
Пакет data.table
. Назначения внутри обычных функций R по-прежнему создают промежуточную копию темп. Единственный способ избежать этого - переопределить [<- как это сделал Мэтт Доул.
Мне любопытно, какие вопросы были отклонены за "передача глобальных переменных в функции" ... это неизбежно во всех, кроме самой строгой среды. Я могу поверить в обратное: доступ к глобальным переменным (даже изменение) изнутри функции без передачи, нарушение лексической области видимости. Бывают случаи, когда чисто функциональный метод может оказаться неэффективным, но неконтролируемый побочный эффект чрезвычайно затрудняет отладку и сопровождение кода. К сожалению, как было предложено в @ 42-, R почти полностью посвящен ссылкам за копированием и копированию при записи, при этом data.table
является заметным исключением.
В этом случае пригодится data.table
. Например: изменить вместо выбранных столбцов cols <- names(dt)[c(1, 5, 10)]; dt[, (cols) := lapply(.SD, function(x) x/mean(x)), .SDcols = cols]
@Tung, в вашем решении мне любопытно, сколько памяти используется? Насколько я понимаю, data.table создает два объекта в памяти (исходную таблицу данных и таблицу со средним масштабом), а затем заменяет один другим? Или каждый столбец в исходной таблице заменяется сразу после вычисления его нового среднецентрованного значения?
Этот вопрос уже обсуждался здесь:
Передать объект функции, не копируя его при изменении
Ваш второй подход на самом деле не решает проблему. Вот тест, который я провел с результатами mem_used ()
library(pryr)
mem_used()
#41.3 MB
x <- matrix(1:1000000000, ncol=1000)
mem_used()
#4.04GB
f2<- function(x){
print(mem_used())
x = deparse(substitute(x))
print(mem_used())
x = get(x, envir = globalenv())
x<- x+1
print(mem_used())
x
}
x <- f2(x)
#4.04 GB
#4.04 GB
#12 GB
mem_used()
#8.04GB
Хорошо знать. Я обновлю свой вопрос, чтобы отразить это. Спасибо!
Я почти уверен, что предложенное вами решение по-прежнему создаст копию внутри f, но мне было бы любопытно его протестировать.