我有一个嵌套的数据列表。它的长度是132,每一项是一个长度为20的列表。是否有一种快速的方法可以将这种结构转换为具有132行和20列数据的数据帧?

下面是一些示例数据:

l <- replicate(
  132,
  as.list(sample(letters, 20)),
  simplify = FALSE
)

当前回答

l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)

其他回答

对于像从嵌套JSON中获得的3级或更多级别的深度嵌套列表的一般情况:

{
"2015": {
  "spain": {"population": 43, "GNP": 9},
  "sweden": {"population": 7, "GNP": 6}},
"2016": {
  "spain": {"population": 45, "GNP": 10},
  "sweden": {"population": 9, "GNP": 8}}
}

考虑一下melt()将嵌套列表转换为高格式的方法:

myjson <- jsonlite:fromJSON(file("test.json"))
tall <- reshape2::melt(myjson)[, c("L1", "L2", "L3", "value")]
    L1     L2         L3 value
1 2015  spain population    43
2 2015  spain        GNP     9
3 2015 sweden population     7
4 2015 sweden        GNP     6
5 2016  spain population    45
6 2016  spain        GNP    10
7 2016 sweden population     9
8 2016 sweden        GNP     8

接着是dcast(),然后再次扩大到一个整洁的数据集,其中每个变量组成一个a列,每个观察值组成一行:

wide <- reshape2::dcast(tall, L1+L2~L3) 
# left side of the formula defines the rows/observations and the 
# right side defines the variables/measurements
    L1     L2 GNP population
1 2015  spain   9         43
2 2015 sweden   6          7
3 2016  spain  10         45
4 2016 sweden   8          9

我发现的每个解决方案似乎只适用于列表中的每个对象都具有相同的长度。当列表中对象的长度不相等时,我需要将列表转换为data.frame。下面是我提出的基于R的解决方案。毫无疑问,这是非常低效的,但它似乎确实有效。

x1 <- c(2, 13)
x2 <- c(2, 4, 6, 9, 11, 13)
x3 <- c(1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13)
my.results <- list(x1, x2, x3)

# identify length of each list
my.lengths <- unlist(lapply(my.results, function (x) { length(unlist(x))}))
my.lengths
#[1]  2  6 20

# create a vector of values in all lists
my.values <- as.numeric(unlist(c(do.call(rbind, lapply(my.results, as.data.frame)))))
my.values
#[1]  2 13  2  4  6  9 11 13  1  1  2  3  3  4  5  5  6  7  7  8  9  9 10 11 11 12 13 13

my.matrix <- matrix(NA, nrow = max(my.lengths), ncol = length(my.lengths))

my.cumsum <- cumsum(my.lengths)

mm <- 1

for(i in 1:length(my.lengths)) {

     my.matrix[1:my.lengths[i],i] <- my.values[mm:my.cumsum[i]]

     mm <- my.cumsum[i]+1

}

my.df <- as.data.frame(my.matrix)
my.df
#   V1 V2 V3
#1   2  2  1
#2  13  4  1
#3  NA  6  2
#4  NA  9  3
#5  NA 11  3
#6  NA 13  4
#7  NA NA  5
#8  NA NA  5
#9  NA NA  6
#10 NA NA  7
#11 NA NA  7
#12 NA NA  8
#13 NA NA  9
#14 NA NA  9
#15 NA NA 10
#16 NA NA 11
#17 NA NA 11
#18 NA NA 12
#19 NA NA 13
#20 NA NA 13

扩展@Marek的回答:如果你想避免字符串变成因素和效率不是一个问题,尝试一下

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)

或者你可以使用tibble包(来自tidyverse):

#create examplelist
l <- replicate(
  132,
  as.list(sample(letters, 20)),
  simplify = FALSE
)

#package tidyverse
library(tidyverse)

#make a dataframe (or use as_tibble)
df <- as_data_frame(l,.name_repair = "unique")