【问题标题】:Unlisting nested lists and without loosing object classes取消列出嵌套列表且不丢失对象类
【发布时间】:2018-02-07 11:03:46
【问题描述】:

在上一篇关于coercion of variables into their appropriate format 的帖子之后,我意识到问题出在unlist():ing 上,它似乎杀死了变量的对象类。

考虑以下结构的嵌套列表 (myList)

> str(myList)
List of 2
 $ lst1:List of 3
  ..$ var1: chr [1:4] "A" "B" "C" "D"
  ..$ var2: num [1:4] 1 2 3 4
  ..$ var3: Date[1:4], format: "1999-01-01" "2000-01-01" "2001-01-01" "2002-01-01"
 $ lst2:List of 3
  ..$ var1: chr [1:4] "Q" "W" "E" "R"
  ..$ var2: num [1:4] 11 22 33 44
  ..$ var3: Date[1:4], format: "1999-01-02" "2000-01-03" "2001-01-04" "2002-01-05"

在最低级别包含不同的对象类型(characternumericDate)。我一直在使用

myNewLst <- lapply(myList, function(x) unlist(x,recursive=FALSE))
result <- do.call("rbind", myNewLst)

得到我的结果矩阵的所需结构。但是,这会为所有变量强制转换为 character,如下所示:

> str(result)
 chr [1:2, 1:12] "A" "Q" "B" "W" "C" "E" "D" "R" "1" "11" "2" "22" "3" "33" "4" "44" "10592" "10593" "10957" "10959" "11323" "11326" ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:2] "lst1" "lst2"
  ..$ : chr [1:12] "var11" "var12" "var13" "var14" ...

阅读post on a similar issue 后,我尝试使用do.call("c", x)

myNewLst <- lapply(myList, function(x) do.call("c", x))
result <- do.call("rbind", myNewLst)

不幸的是,这也导致所有变量都是characters,这是我的第一次尝试。所以我的问题是:如何在不丢失低级变量的对象类的情况下取消列出嵌套列表?是否有替代方案可以达到预期的效果?

myList 的可重现代码:

myList <- list(
  "lst1" = list(
    "var1" = c("A","B","C","D"),
    "var2" = c(1,2,3,4),
    "var3" = c(as.Date('1999/01/01'),as.Date('2000/01/01'),as.Date('2001/01/01'),as.Date('2002/01/01'))
  ),
  "lst2" = list(
    "var1" = c("Q","W","E","R"),
    "var2" = c(11,22,33,44),
    "var3" = c(as.Date('1999/01/02'),as.Date('2000/01/03'),as.Date('2001/01/4'),as.Date('2002/01/05'))
  )
)

【问题讨论】:

  • 你能展示你试图创建的对象的结构吗?不可能在矩阵中混合字符日期整数等,但如果这是您希望实现的,您可以轻松地将列表强制转换为单个数据框

标签: r list coercion


【解决方案1】:

您可以使用Reduce()do.call() 将所有数据框组合到一个数据帧中。下面的代码应该可以工作

      Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F))

        var1 var2       var3
      1    A    1 1999-01-01
      2    B    2 2000-01-01
      3    C    3 2001-01-01
      4    D    4 2002-01-01
      5    Q   11 1999-01-02
      6    W   22 2000-01-03
      7    E   33 2001-01-04
      8    R   44 2002-01-05

类也被维护:

  mapply(class,Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F)))
        var1        var2        var3 
 "character"   "numeric"      "Date"

【讨论】:

  • 正是我想要的,非常感谢:)
  • 顺便说一句,有没有更有效的替代方案?我大约 2 秒 970 obs。使用此解决方案在我的机器上包含 27 个变量
  • 尝试将Reduce()更改为do.call(),同时保持函数内的所有其余部分并比较两者的时间
  • @ComfortEagle ;试试data.table::rbindlist(myList),虽然我认为你的数据不够大,无法真正受益。
【解决方案2】:

如果您的目标是将此列表列表转换为单个数据框,则以下代码应该可以工作:

result <- data.frame(var1 = unlist(lapply(myList, function(e) e[1]), use.names = FALSE), 
                     var2 = unlist(lapply(myList, function(e) e[2]), use.names = FALSE),
                     var3 = as.Date(unlist(lapply(myList, function(e) e[3]), use.names = FALSE), origin = "1970-01-01"))

这给出了:

> result
  var1 var2       var3
1    A    1 1999-01-01
2    B    2 2000-01-01
3    C    3 2001-01-01
4    D    4 2002-01-01
5    Q   11 1999-01-02
6    W   22 2000-01-03
7    E   33 2001-01-04
8    R   44 2002-01-05

当然,如果每个列表中有多个变量,您可以使用 for 循环使代码更简洁。

【讨论】:

  • 你的答案似乎也放弃了日期类(ps 我认为 do.call(rbind, lapply(myList, as.data.frame))会更简洁一些并保留日期类)
  • 对不起,我没有注意到,已经相应地编辑了答案
  • 是的,do.call 解决方案更加优雅!
猜你喜欢
  • 2021-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-28
  • 1970-01-01
  • 2018-05-18
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多