将 R 中的列表嵌套转换为数据框。

50
我有一个列表,称为listHolder,它包含5个元素。 listHolder中的每个元素都是一个包含大约160个元素的数字数据列表。
我需要将这个列表转换成一个长度为5的data.frame,其中每个元素都是一个包含大约160个元素的数字向量。
但是我尝试过的所有方法都不行,从迭代遍历列表并将每个元素用as.numeric(unlist(listHolder[[i]]))转换,到...
data.frame(matrix(unlist(listHolder), nrow = length(totalKeywords), byrow = T))

最终会创建一个长度为160左右的数据框,每个元素都是一个具有5个或更多元素的数字向量。

我该如何做到我想要的呢?

尝试使用data.frame(matrix(unlist(totalKeywords), nrow=132, byrow=T))会得到与我想要的相反的结果 - 160个小项目,每个项目都有5个元素。


17
请尝试使用do.call(rbind, listHolder) - dimitris_ps
1
可能是R列表转数据框的重复问题。 - user3710546
我认为他想要将每个列中的listHolder项目转换,因此应该使用cbind而不是rbind - Molx
2
为什么不使用 as.data.frame(listHolder) - shadow
你能提供listHolder的样本数据吗? - Hack-R
当然:打印(listHolder) = [[1]] [1] 0 0 0 0 1 1 0 1 0 1...(持续160个或更多),[[2]] [1] 4 0 2 4 23 0 3 2 4...(持续160个或更多),[[3]] [1] 2 3 1 3 3....等等。我尝试了"R列表转数据帧"中的解决方案,最后得到了160个名为"X1"、"X2"、"X3"等的对象,每个对象都有五个成员。使用do.call(cbind, listHolder)可以给我一个看起来像矩阵的东西——列用[,1]、[,2]、[,3]等标记,行用[1,]、[2,]、[3,]等标记。 - Bacter
6个回答

51

正如@dimitris_ps之前提到的那样,答案可能是:

do.call(rbind, listHolder)

由于do.call自然地“剥离”1个层级的“列表中的列表”,获取一个列表,而不是一个列表的列表。

之后,rbind可以处理列表中的元素并创建一个矩阵


4
如果“行”被命名为列表,这将非常有用,因为它可以保留列表的名称(假设名称是一致的)。 - tmrlvi
...而且它不像上面的'unlist'那样改变数据类型。这就是答案! - ned
非常有用!不过,是否有一种方法将每个列表的编号/名称包含在最终数据框中? - vog

32

需要固定nrow的值。我已将您的代码更正如下:

dd  <-  as.data.frame(matrix(unlist(listHolder), nrow=length(unlist(listHolder[1]))))

6
有什么方法可以保留数据类型吗?按照此方法,如果一列是POSIXct类型,它会被转换为chr类型。 - Rafael
可以通过使用“Reduce”(如我的答案中所示)来保留类型。 - luco00

18

这是我找到的最简单的解决方案。

library(jsonlite)
library(purrr)
library(data.table)

dt_list <- map(list_of_lists, as.data.table)
dt <- rbindlist(dt_list, fill = TRUE, idcol = T)

dt

对我来说唯一可行的方法。不过,仍无法像之前要求的那样保留POSIXct - Marco
你真的需要 library(jsonlite) 吗?你可以用 library(magrittr) 替换它并一次完成操作:map(list_of_lists, as.data.table) %>% rbindlist(...) - Valentin_Ștefan

13

我常常遇到这个问题,通常会根据当前答案来适应我的需求。

当前的答案要么混淆变量类型,要么不能很好地处理正确的列表嵌套列表(注意复数形式)。

简而言之,请使用以下内容:

当listHolder中的每个元素都包含数据框的一列时,此方法有效。

df <- data.frame(lapply(listHolder, function(x) Reduce(c, x)))

当listHolder中的每个元素都包含数据框的一行时,此方法有效

df <- do.call(rbind, lapply(listHolder, data.frame))

最小工作示例(列表元素为列)

以下代码提供了一个最小工作示例,并审查了其他答案。我建议使用#通用方法

listHolder <- list(
  A = rep(list(1, 2), 80),
  B = rep(c(3, 4), 80),
  C = rep(c("a", "b"), 80),
  D = rep(list("c", "d"), 80),
  E = rep(as.POSIXct(10485849600, origin = "1582-10-14", tz = "GMT"), 160)
)


# @Noha's Answer
data1  <-  as.data.frame(matrix(unlist(listHolder), nrow=length(unlist(listHolder[1]))))
# Try this (mess up with types)
str(data1)

# @Camilo's Answer
data2 <- data.frame(do.call(cbind, listHolder))
# Try this (each column becomes a list)
str(data2)

# General Approach
data3 <- data.frame(lapply(listHolder, function(x) Reduce(c, x)))
str(data3)

最小工作示例(列表元素是行)

当列表中的每个元素都应该包含数据帧中的一行时,应使用此代码。

listHolder <- list(
  row1 = list(name = "foo", surname = "bar", age = 90),
  row2 = list(name = "foo", surname = "foo", age = 29),
  row3 = list(name = "bar", surname = "foo", age = 45),
  row4 = list(name = "bar", surname = "bar", age = 10)
)

# A simple rbind won't work (each column is still a list)
data1 <- do.call(rbind, listHolder)
str(data1)

# General Approach (now it's better)
data2 <- do.call(rbind, lapply(listHolder, data.frame))
str(data2)

谢谢你的回答。这正是我正在寻找的,但我的一些数据有点棘手。某些列表中的某些元素具有 NULL 值。这些值被忽略了,因此列表的长度不同,并且出现错误。您是否有解决方案可以处理这种情况? - Soccerama
我猜你需要先清理列表。例如,你可以尝试这个:listHolder <- lapply(listHolder, function(x) { Map(function(z){ifelse(is.null(z), NA, z)}, x) })。这将用NA替换子列表中的所有NULL值。然后你可以根据需要替换数据框中的值,或使用其他替换值。但是对于向量,这种方法不起作用。也就是说,如果你的主列表包含长度不同的向量,你需要进一步清理(在这种情况下,我可能会选择使用循环)。 - luco00

11
这可以实现类似的结果,但更加直观易懂(至少对我来说是这样)。
#Generate fake data 
listoflists=list(c(1,'a',3,4),c(5,'b',6,7))

#Convert to a dataframe, transpose, and convert the resulting matrix back to a dataframe
df= as.data.frame(t(as.data.frame(listoflists)))

#Strip out the rownames if desired
rownames(df)<-NULL

#Show result
df

6
这不是一个列表的列表,而是原子向量的列表(由于你有不同的数据类型,它们被强制转换为字符)。 - Victor Mayrink

-1

我认为这比之前的解决方案更容易:

mydf = data.frame(x1 = c('a', 'b', 'c'))
mylist = list(c(4, 5), c(4, 5), c(4, 5))
mydf$x2 = mylist
print(mydf)
  x1   x2
1  a 4, 5
2  b 4, 5
3  c 4, 5

3
不是一个列表的列表。 - Victor Mayrink

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接