Изучение содержимого файла .rdata путем присоединения к новой среде - возможно? - PullRequest
9 голосов
/ 01 июля 2011

Меня интересует перечисление объектов в файле RDATA и загрузка только выбранных объектов, а не всего набора (в случае, если некоторые из них могут быть большими или уже могут существовать в среде). Я не совсем понимаю, как это сделать, когда в именах есть конфликты, так как attach() работает не так хорошо.

1: Для проверки содержимого файла данных R без его загрузки: Этот вопрос похож, но отличается от вопроса, заданного на с перечислением содержимого файла данных R без загрузки

В этом случае предлагаемое решение было:

attach(filename)
ls(pos = 2)
detach()

Если существуют конфликты именования между объектами в файле и объектами в глобальной среде, появляется это предупреждение: The following object(s) are masked _by_ '.GlobalEnv':

Я пытался создать новую среду, но я не могу присоединиться к этому. Например, это приводит к той же ошибке:

lsfile   <- function(filename){
  tmpEnv <- new.env()
  evalq(attach(filename), envir = tmpEnv)
  tmpls <- ls(pos = 2)
  detach()
  return(tmpls)
}
lsfile(filename)

Возможно, я напутал с evalq (или eval). Есть ли другой способ избежать конфликта имен?

2: Если я хочу получить доступ к объекту - если нет конфликтов имен, я могу просто поработать с объектом из файла .rdat или скопировать его в новый. Если есть конфликты, как получить доступ к объекту в пространстве имен файла?

Например, если мой файл - "sample.rdat", а объект - surveyData, а объект surveyData уже существует в глобальной среде, то как я могу получить к нему доступ из пространства имен file:sample.rdat?

В настоящее время я решаю эту проблему, загружая все во временную среду, а затем копирую все, что нужно, но это неэффективно.

Ответы [ 4 ]

19 голосов
/ 02 января 2012

Поскольку на этот вопрос только что ссылались, давайте уточним две вещи:

  1. attach() просто вызывает load(), так что на самом деле нет смысла использовать его вместо load

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

    e = local({load("foo.RData"); environment()})
    

    Затем вы можете использовать ls(e) и получить доступсодержимое как e$x.Вы все еще можете использовать attach в среде, если вы действительно хотите использовать ее в пути поиска.

FWIW .RData файлы не имеют индекса (объекты хранятся в одном большом pairlist)так что вы не можете перечислить содержащиеся объекты без загрузки.Если вам нужен удобный доступ, преобразуйте его в формат отложенной загрузки, который просто добавляет индекс, чтобы каждый объект мог быть загружен отдельно (см. Получить конкретный объект из файла Rdata )

6 голосов
/ 03 июля 2011

Я просто использую аргумент env= для load():

> x <- 1; y <- 2; z <- "foo"
> save(x, y, z, file="/tmp/foo.RData")
> ne <- new.env()
> load(file="/tmp/foo.RData", env=ne)
> ls(env=ne)
[1] "x" "y" "z"
> ne$z
[1] "foo"
> 

Стоимость этого подхода заключается в том, что вы действительно читаете весь файл RData - но с другой стороны, кажется,быть неизбежным в любом случае, так как ни один другой метод не предлагает список «содержимого» такого файла.

4 голосов
/ 03 июля 2011

Вы можете подавить предупреждение, установив warn.conflicts=FALSE при вызове на attach. Если объект маскируется одним объектом в глобальной среде, вы можете использовать get для извлечения его из прикрепленных данных.

x <- 1:10
save(x, file="x.rData")
#attach("x.rData", pos=2, warn.conflicts=FALSE)
attach("x.rData", pos=2)
(x <- 1)
# [1] 1
(x <- get("x", pos=2))
# [1]  1  2  3  4  5  6  7  8  9 10
2 голосов
/ 03 июля 2011

Спасибо @Dirk и @ Joshua.

У меня было прозрение. Команда / пакет foreach с SMP или MC, по-видимому, создает среды, которые наследуют, но не конфликтуют с глобальной средой.

lsfile   <- function(list_files){
    aggregate_ls = foreach(ix = 1:length(list_files)) %dopar% {
      attach(list_files[ix])
      tmpls <- ls(pos = 2)
      return(tmpls)
    }
  return(aggregate_ls)
}

lsfile("f1.rdat")
lsfile(dir(pattern = "*rdat"))

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

Итак, вопрос № 1 может быть решен либо игнорированием предупреждений (как предложено @ Джошуа), либо с помощью любой магической foreach призыва.

Для части 2, загружающей объект, я думаю, у @Joshua есть правильная идея - «get» подойдет.

Магия foreach также может работать, используя опцию .noexport. Однако это сопряжено с риском: все, что конкретно не исключено, будет унаследовано / экспортировано из глобальной среды (я мог бы сделать ls(), но всегда есть возможность присоединения наборов данных). В целях безопасности это означает, что get() все еще должен использоваться, чтобы избежать риска конфликта имен. Загрузка в подсредство позволяет избежать конфликта имен, но не избежать загрузки ненужных объектов.

@ Ответ Иисуса Навина гораздо проще, чем мой обход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...