Назначить несколько объектов.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)