如何取消列表并将顶级名称保留为 R 中的新变量

How to unlist a list and keep the names of the top level as a new variable in R

有没有一种简单的方法来取消列出列表并将一级的名称保留为新变量?

工作示例:

# Input list
my_list <- list(Ticker1 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 1:10),
                Ticker2 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 11:20),
                Ticker3 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 21:30))

# Desired data frame
my_df_goal <- as.data.frame(list(Ticker = c(rep("Ticker1", 10), rep("Ticker2", 10), rep("Ticker3", 10)),
                                 date = rep(seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), 3),
                                 Value = 1:30))

在 Whosebug 上也有关于取消列表的类似问题,但我无法解决我的问题。

一种方法可能是

my_df <- as.data.frame(rlist::list.flatten(my_list))

# Same result:
my_df2 <- as.data.frame(unlist(my_list,recursive = F))

#Edit: just noticed that you do not need to unlist first to get the same result:
my_df3 <- as.data.frame(my_list)

然后尝试从新变量名中提取 Ticker。但我希望有一个更简单的解决方案。

我也试过my_df4 <- reshape2::melt(my_list),但这没有帮助。我感觉 purrr 包可能有这个功能,但我不熟悉这个包。

我很高兴能得到任何帮助!

非常感谢

使用data.table::rbindlist:

data:table::rbindlist(my_list, idcol = "Ticker")

或者,在 tidyverse:

library(tidyverse)

my_list %>% 
  enframe() %>% 
  unnest_wider(value) %>% 
  unnest(cols = c(date, Value))

#  A tibble: 30 x 3
   name    date       Value
   <chr>   <date>     <int>
 1 Ticker1 2021-01-01     1
 2 Ticker1 2021-01-02     2
 3 Ticker1 2021-01-03     3
 4 Ticker1 2021-01-04     4
 5 Ticker1 2021-01-05     5
 6 Ticker1 2021-01-06     6
 7 Ticker1 2021-01-07     7
 8 Ticker1 2021-01-08     8
 9 Ticker1 2021-01-09     9
10 Ticker1 2021-01-10    10
# ... with 20 more rows

dplyrs bind_rows 应该可以解决问题:

library(dplyr)

bind_rows(my_list, .id = "Ticker")

这个returns

# A tibble: 30 x 3
   Ticker  date       Value
   <chr>   <date>     <int>
 1 Ticker1 2021-01-01     1
 2 Ticker1 2021-01-02     2
 3 Ticker1 2021-01-03     3
 4 Ticker1 2021-01-04     4
 5 Ticker1 2021-01-05     5
 6 Ticker1 2021-01-06     6
 7 Ticker1 2021-01-07     7
 8 Ticker1 2021-01-08     8
 9 Ticker1 2021-01-09     9
10 Ticker1 2021-01-10    10
# ... with 20 more rows

一旦我们意识到每个代码的子列表只是 2 个长度相等的列表,那么我们可以将其视为 3 个 dataframes 的列表,每个列表有 2 列,并且我们可以简单地调用 rowbind:

do.call(rbind, lapply(my_list, data.frame))
#                  date Value
# Ticker1.1  2021-01-01     1
# Ticker1.2  2021-01-02     2
# Ticker1.3  2021-01-03     3
# Ticker1.4  2021-01-04     4
# Ticker1.5  2021-01-05     5
# ...

但是我们想要将名称列表作为一个新列,我们需要额外的步骤:

do.call(rbind, 
        lapply(names(my_list), function(i){
          data.frame(Ticker = i, my_list[[ i ]])
        }))
#     Ticker       date Value
# 1  Ticker1 2021-01-01     1
# 2  Ticker1 2021-01-02     2
# 3  Ticker1 2021-01-03     3
# 4  Ticker1 2021-01-04     4
# 5  Ticker1 2021-01-05     5
# ...

rowbinding 多个 dataframes:

之后查看其他选项以将 ID 作为新列获取
  • Combine (rbind) data frames and create column with name of original data frames