从列表列表的元素自动创建变量 R

Create Variables from elements of a List of Lists Automatically R

提问人: 提问时间:6/25/2021 更新时间:6/26/2021 访问量:122

问:

我有一个列表,如下所示

str(list_ts_split)
List of 5
 $ date    :List of 2
  ..$ train: Time-Series [1:24] from 2019 to 2021: 1.55e+09 1.55e+09 1.55e+09 1.55e+09 
1.56e+09 ...
  ..$ test : Time-Series [1:6] from 2021 to 2021: 1.61e+09 1.61e+09 1.61e+09 1.62e+09 1.62e+09 
...
 $ actualB1:List of 2
  ..$ train: Time-Series [1:24] from 2019 to 2021: 5463 7618 3745 6760 5856 ...
  ..$ test : Time-Series [1:6] from 2021 to 2021: 5535 7326 6195 2435 3041 ...
     $ actualB2:List of 2
  ..$ train: Time-Series [1:24] from 2019 to 2021: 6523 1734 9544 4687 8076 ...
  ..$ test : Time-Series [1:6] from 2021 to 2021: 3647 9272 4974 5931 1459 ...
 $ actualAx:List of 2
  ..$ train: Time-Series [1:24] from 2019 to 2021: 193 200 310 149 719 357 470 623 678 533 ...
  ..$ test : Time-Series [1:6] from 2021 to 2021: 274 142 968 831 178 184
 $ actualAy:List of 2
  ..$ train: Time-Series [1:24] from 2019 to 2021: 3053 4351 3284 2155 1805 ...
  ..$ test : Time-Series [1:6] from 2021 to 2021: 8236 1585 2324 5692 4249 ...

我可以使用下面的代码访问列表列表的元素

df1_tstrain <- list_ts_split$actualB1$train

df1_tstest <- list_ts_split$actualB1$test

list_ts_split $actualB1$train
      Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
 2019 5463 7618 3745 6760 5856 2645 4061 1162 6829 7584 8383 4016
 2020 2827 1666 3753 2004 1757 9360 5989 9031 1584 1435 8365 9209

 list_ts_split$actualB1$test
       Jan  Feb  Mar  Apr  May  Jun
  2021 5535 7326 6195 2435 3041 2737

编辑1:我的问题是,是否有任何方法可以创建一个循环或使用一个函数来做同样的事情 df1_tstrain <- actualB1$train 没有我在全局环境中将值硬编码为变量名称??

编辑2:

我现在正在尝试如下所示的东西

for (i in 1:length(list_ts_split)){
assign(paste0("tstrain",i}.as.data.frame(list_ts_split[[i]]))
}
R 函数 循环 时间序列 数据操作

评论

0赞 IRTFM 6/25/2021
我无法弄清楚“自动”是什么意思。看来你已经知道该怎么做了。你最后的代码显然不是为了在实践中使用,而是试图传达某种在实现中与df1_tstrain <- list_ts_split$actualB1$train
0赞 IRTFM 6/25/2021
不。不要使用通讯来澄清问题。使用编辑工具。“在全局环境中自动创建一个变量,而无需我将其硬编码为变量名称”是什么意思。你为什么不想给它起个名字?
0赞 6/25/2021
例如,假设我有 100 个列表,这 100 个列表中的每一个都包含 2 个元素。我不想手动输入我的 R 脚本......train1 <- list_ts_split$actualAx$train 和 test1 <- list_ts_split$actualAx$test ...100次。我想要一个可以创建 train1 的 100 个变量的循环/函数......train100 和 test1...test100 对我来说,而不是我写 200 行。我希望这能澄清我在说什么
0赞 Ronak Shah 6/25/2021
在全局环境中创建多个对象(如 等)不是一个好做法。它们污染了全球环境,很难管理它们。在此之后,您的下一步是什么?您可以使用 on 直接对每个列表执行该步骤。df1_tstraindf1_tstestlapplylist_ts_split
0赞 6/25/2021
是的,我认为是这样。我找到了一个效果很好的不同解决方案。我使用 do.call(“rbind”,list_ts_split) 创建了每个训练/测试的列表,这样我就可以用 list_ts_split[[1]] 等指定它们。

答:

0赞 Liman 6/25/2021 #1

你没有一个工作的例子,所以我不确定我是否理解你的问题。话虽如此,这里有一些可以尝试的东西。

## Some data to work with
lst <- list(
  date = list(
    train = 2000:2010,
    test  = 2011:2021
  ),
  actualB1 = list(
    train = 2000:2010,
    test  = 2011:2021
  ),
  actualAx = list(
    train = 2000:2010,
    test  = 2011:2021
  )
)
## A function to subset the list at levels 1 and 2.
f <- function(lst, level_1, level_2){
  # l1 <- lst[[level_1]]
  # l1[[level_2]] 
  l1 <- sapply(X = lst, FUN = "[", level_2, simplify = FALSE)
  l1[[level_1]]
}
## testing the function on the list specifying the names of the 2 levels
test <- f(lst = lst, level_1 = 'actualB1', level_2 = 'train')
test

我仍然不确定我是否理解这个问题,但这是我在递归函数中提出的另一个想法。

## Data

lst <- list(
  date = data.frame(
    train = 2000:2005,
    test  = 2005:2010
  ),
  actualB1 = data.frame(
    train = 2010:2015,
    test  = 2015:2020
  ),
  actualAx = data.frame(
    train = 2020:2025,
    test  = 2030:2035
  )
)

# Function

f <- function(lst){
  names_lst <- names(lst)
  lapply(X = names_lst, function(i){
    if(inherits(lst[[i]], what = 'data.frame', which = TRUE)){
      names_i <- names(lst[[i]])
      lapply(X = names_i, function(j){
        obj_name <- paste(i, j, sep = "_")
        assign(obj_name, lst[[i]][[j]], envir = .GlobalEnv)
      })
    } else {
      f (lst)
    }
  })
}

# Function called on Data

test <- f(lst = lst)

Overview of the global environment

我不确定我是否理解您的问题的理由是,我似乎不明白为什么人们想要继续子集列表并将结果分配给新对象。

我认为,如果你想对你正在子集的数据进行进一步的分析,你需要重新考虑你的方法。虽然上面的函数通常会检索列表不同嵌套级别的名称,但它可能会遇到错误,具体取决于您的设置。这可能表明您可能需要重新考虑您的方法。尝试添加更多级别的嵌套,您最终可能会遇到该错误。在我的机器上,以下导致我出现该错误:C stack usage <number> is too close to the limitlst

lst <- list(
  date = data.frame(
    train   = 2000:2005,
    test    = 2005:2010
  ),
  actualB1  = data.frame(
    train   = 2010:2015,
    test    = 2015:2020
  ),
  actualAx  = list(
    up      = data.frame(
      train = 2020:2025,
      test  = 2030:2035
    ),
    sub     = data.frame (
      train = 2040:2045,
      test  = 2045:2050
    )
  )
)
test <- f(lst = lst) # Error: C stack usage  15926032 is too close to the limit

评论

0赞 6/25/2021
是的,这很有帮助!为了进一步澄清,我正在尝试为每个火车创建一个向量或数据帧,并在循环中的每个列表中进行测试。因此,在您的 lst 示例中,由于有 3 个列表(date、actualB1、actualAx),我希望在某种循环中有 6 个向量/dfs(因为每个列表中有 2 个元素)。基本上,如果我有 100 个列表,每个列表包含 2 个元素(date=,actualB1=,actualA1,actualG1,etc......到 100),对于 100*2 向量/dfs,我需要 200 行代码。试图使我的代码更简洁
0赞 6/25/2021
我知道如何通过在您的示例中使用 lst$date$train 将 2000:2010 提取到变量 (date_train<- lst$date$train) 中来“手动”完成,但如果我有 100 个不同的训练/测试,我不想编写代码 200 次......(date_train1....date_train100 <- lst$the_100th_list_name$train) 所以我想要一种循环或函数形式的“自动化方式”。也许这在 R 中太难了。我希望这是有道理的
0赞 Liman 6/26/2021
好的,看看我的编辑,让我发布!