Подтвердить что ты не робот

Пустое окружение R становится большим файлом при сохранении

Я получаю поведение, которое я не понимаю при сохранении среды. Приведенный ниже код демонстрирует проблему. Я ожидал, что два файла (far-too-big.RData и right-size.RData) будут одинакового размера, а также очень малы, потому что среды, которые они содержат, пусты.

Фактически, far-too-big.RData заканчивается тем же размером, что и bigfile.RData.

Получаю те же результаты, используя 2.14.1 и 2.15.2, как на WinXP 5.1 SP3. Может ли кто-нибудь объяснить, почему это происходит?

Оба far-too-big.RData и right-size.RData при загрузке в новый сеанс R, похоже, ничего не содержат. т.е. они возвращают character(0) в ответ на ls(). Однако, если я переключу сохранение, включив ascii=TRUE и откройте результат в текстовом редакторе, я вижу, что far-too-big.RData содержит данные в bigfile.RData.

a <- matrix(runif(1000000, 0, 1), ncol=1000)
save(a, file="bigfile.RData")
fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    save(test, file="far-too-big.RData")
    test1 <- new.env(parent=globalenv())
    save(test1, file="right-size.RData")
}
fn()
4b9b3361

Ответ 1

Это не моя область знаний, но я считаю, что такие среды работают так.

  • Любое окружение наследует все в родительской среде.
  • Все вызовы функций создают собственную среду.

Результат выше в вашем случае:

  • Когда вы запустите fn(), он создает свою собственную локальную среду (зеленый), родительский по умолчанию - globalenv() (серый).
  • Когда вы создаете среду test (красный) внутри fn(), ее родительский элемент по умолчанию имеет значение fn() environment (зеленый). test будет включать объект a.
  • Когда вы создаете среду test1 (синий) и явно указываете, что ее родительский элемент globalenv(), он отделен от среды fn() и не наследует объект a.

Поэтому при сохранении test вы также сохраняете (несколько скрытую) копию объекта a. Этого не происходит, если вы сохраняете test1, поскольку он не включает объект a.

enter image description here

Update

По-видимому, это более сложная тема, чем я верил. Хотя я мог бы просто процитировать @joris-mays, ответьте сейчас, я бы хотел сделать последний шаг.

Для меня самой интуитивной визуализацией сред была бы древовидная структура, см. ниже, где каждый node является средой, а стрелки указывают на свою соответствующую среду окружения (которую я бы хотел считать такой же, как и ее родительская, но это связано с кадрами и находится за пределами моего мира). Данная среда охватывает все объекты, которые вы можете достичь, перемещаясь по дереву, и она может получить доступ ко всем объектам, которые вы можете достичь, двигая дерево. Когда вы сохраняете среду, вы обнаруживаете, что сохраняете все объекты и среды, которые оба заключены в нее и доступны из нее (за исключением globalenv()).

Однако сообщение с домашним сообщением, как уже указывал Йорис, сохраняет ваши объекты в виде списков, и вам не нужно беспокоиться.

enter image description here

Если вы хотите узнать больше, я могу рекомендовать Норман Матлоффу отличную книгу искусство программирования R. Он нацелен на разработку программного обеспечения в R, а не на первичный анализ данных, и предполагает, что у вас есть хороший опыт программирования. Должен признаться, что я еще не полностью усвоил часть среды, но, поскольку остальная часть книги очень хорошо написана и педагогична, я полагаю, что это тоже.

Ответ 2

Фактически, это наоборот, чем @Backlin показывает: родительская среда - это та, которая окружает другие. Таким образом, в том случае, когда вы определяете, окружающая среда test является локальной средой fn, а окружающая среда test1 является глобальной средой, например:

enter image description here

Среды ведут себя иначе, чем другие объекты в R, в том смысле, что они не копируются при передаче функций или используются в назначениях. Сам объект среды состоит из указателей:

  • кадр (который является парным списком, содержащим значения)
  • окружающая среда (как описано выше)
  • хеш-таблица (которая является либо списком, либо NULL, если среда не хеширована)

Тот факт, что среда содержит указатели, имеет значение. Среда не так просто справиться, они на самом деле очень сложны. Взгляните на код ниже:

> test <- new.env()
> test$a <- 1
> test2 <- test
> test2$a <- 2
> test$a
[1] 2

Итак, единственное, что вы скопировали из test в test2, - это указатели. Если вы измените значение в test2, вы также измените его на test. (Фактически, вы меняете это значение только один раз, но test и test2 указывают оба на один и тот же фрейм).

Когда вы пытаетесь сохранить среду, у R нет выбора, кроме как получить значения для фрейма, хэш-таблицы и окружения и сохранить их. Поскольку окружающая среда является средой сама по себе, R также сохраняет все окружающие среды, пока не достигнет глобальной среды. Поскольку глобальная среда обрабатывается особым образом во внутреннем коде, этот (к счастью) не сохраняется в файле.

Обратите внимание на разницу между окружением окружения и родительским фреймом: Скажем, мы определяем наши функции несколько иначе:

a <- matrix(runif(1000000, 0, 1), ncol=1000)
save(a, file="bigfile.RData")
fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    save(test, file="far-too-big.RData")
    test1 <- new.env(parent=globalenv())
    save(test1, file="right-size.RData")
}

fn2 <- function(){
    z <- matrix(runif(1000000,0,1),ncol=1000)
    fn()
}
fn2()

Теперь мы имеем следующую ситуацию:

enter image description here

Можно подумать, что файл "far-too-large.RData" содержит как матрицу a, так и матрицу z, но это не так. Он содержит только матрицу a. Это связано с тем, что окружающая среда fn является глобальной средой. Родительский кадр fn - это среда fn2, но объект среды, созданный fn, содержит указатель на глобальную среду.

С другой стороны, если мы делаем следующее:

fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    test$b <- a
    test2 <- new.env(parent=test)
    save(test2, file="far-too-big.RData")
}

test2 теперь заключен в две среды (test и среда fun), и обе среды также сохраняются в файле. Таким образом, вы получаете следующую ситуацию:

enter image description here

Независимо от этого, я лично избегаю экономии среды как среды, потому что есть больше вещей, которые могут пойти не так. На мой взгляд, сохранение среды как списка в 99,9% случаев - лучший выбор:

fn2 <- function(){
    load("bigfile.RData")
    test <- new.env()
    test$x <- "something"
    test$fn <- ls
    testlist <- as.list(test)
    save(testlist, file="right-size.RData")
}
fn2()

Если вам нужно, чтобы это была среда, вы можете преобразовать ее при загрузке.

load("right-size.RData")
test <- as.environment(testlist)