Назначить несколько объектов.GlobalEnv из функции

В посте, опубликованном здесь накануне, я задаюсь вопросом, как назначить значения нескольким объектам в глобальной среде изнутри функции. Это моя попытка использования lapply (assign может быть безопаснее, чем <<- но я никогда не использовал его и не знаком с ним).

#fake data set
df <- data.frame(
  x.2=rnorm(25),
  y.2=rnorm(25),
  g=rep(factor(LETTERS[1:5]), 5)
)

#split it into a list of data frames
LIST <- split(df, df$g)

#pre-allot 5 objects in R with class data.frame()
V <- W <- X <- Y <- Z <- data.frame()

#attempt to assign the data frames in the LIST to the objects just created
lapply(seq_along(LIST), function(x) c(V, W, X, Y, Z)[x] <<- LIST[[x]])

Пожалуйста, не стесняйтесь сокращать любые / все части моего кода, чтобы сделать эту работу (или работать лучше / быстрее).

4 ответа

Решение

Обновление 2018-10-10:

Наиболее краткий способ выполнить эту конкретную задачу - использовать list2env() вот так:

## Create an example list of five data.frames
df <- data.frame(x = rnorm(25),
                 g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)

## Assign them to the global environment
list2env(LIST, envir = .GlobalEnv)

## Check that it worked
ls()
## [1] "A"    "B"    "C"    "D"    "df"   "E"    "LIST"

Оригинальный ответ, демонстрирующий использование assign()

Ты прав что assign() это правильный инструмент для работы. это envir Аргумент дает вам точный контроль над тем, где происходит назначение - контроль, который не доступен ни с одним из <- или же <<-,

Так, например, чтобы присвоить значение X к объекту с именем NAME в глобальной среде вы бы сделали:

assign("NAME", X, envir = .GlobalEnv)

В твоем случае:

df <- data.frame(x = rnorm(25),
                 g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)
NAMES <- c("V", "W", "X", "Y", "Z")

lapply(seq_along(LIST), 
       function(x) {
           assign(NAMES[x], LIST[[x]], envir=.GlobalEnv)
        }
)

ls()
[1] "df"    "LIST"  "NAMES" "V"     "W"     "X"     "Y"     "Z"    

Я думаю, что этот вопрос может иметь хорошее пересечение с этим: можно ли создавать списки с этим именем на основе имен входных объектов?

Скажем, вы хотите сделать ту же модификацию набора объектов на лету. Ноlist2env()требуется именованный список, и вы не хотите копировать и вставлять их снова. ЗаимствованиеnamedListфункцию и комбинируя ее с ответом Джоша О'Брайена:

      > namedList <- function(...) {
+   L <- list(...)
+   snm <- sapply(substitute(list(...)), deparse)[-1]
+   if (is.null(nm <- names(L))) nm <- snm
+   if (any(nonames <- nm=="")) nm[nonames] <- snm[nonames]
+   setNames(L ,nm)
+ }
> 
> df_1 <- data.frame(x = 1)
> df_2 <- data.frame(x = 2)
> df_3 <- data.frame(x = 3)
> 
> list2env(lapply(namedList(df_1, df_2, df_3), function(x) {
+   x <- cbind.data.frame(x, y = "B")
+ }), envir = .GlobalEnv)
<environment: R_GlobalEnv>
> 
> df_1
  x y
1 1 B
> df_2
  x y
1 2 B
> df_3
  x y
1 3 B

Если у вас есть список имен объектов и путей к файлам, вы также можете использовать mapply:

object_names <- c("df_1", "df_2", "df_3")
file_paths   <- list.files({path}, pattern = ".csv", full.names = T)
    
mapply(function(df_name, file) 
           assign(df_name, read.csv(file), envir=.GlobalEnv),
       object_names,
       file_paths)
  • я использовал list.files()для создания вектора всех файлов.csv в определенном каталоге. Но file_paths можно записать или сконструировать любым способом.
  • Если файлы, которые вы хотите прочитать, находятся в текущем рабочем каталоге, то file_paths можно заменить вектором символов имен файлов.
  • В приведенном выше коде вам нужно заменить {path} строкой пути к желаемому каталогу.

Это демонстрирует, как разделить вложенный фрейм данных на объекты в глобальной среде с помощью tidyverseфункции:

      library(tidyverse)
library(palmerpenguins)

penguins %>% 
  group_nest(species) %>% 
  deframe() %>% 
  list2env(.GlobalEnv)
Другие вопросы по тегам