我有一个嵌套的数据列表。它的长度是132,每个项目都是一个长度为20的列表。是否有一种快速的方法将该结构转换为具有132行和20列数据的数据帧?
以下是一些示例数据:
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
我有一个嵌套的数据列表。它的长度是132,每个项目都是一个长度为20的列表。是否有一种快速的方法将该结构转换为具有132行和20列数据的数据帧?
以下是一些示例数据:
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
Answers:
假设您的列表列表称为l
:
df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=T))
上面的代码将所有字符列转换为因子,为避免这种情况,您可以向data.frame()调用添加参数:
df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
用 rbind
do.call(rbind.data.frame, your_list)
编辑:返回的data.frame
是list
的旧版本,而不是矢量(如@IanSudbery在注释中指出的)。
rbind(your_list)
返回1x32列表矩阵?
do.call
将的元素your_list
作为参数传递给rbind
。等于rbind(your_list[[1]], your_list[[2]], your_list[[3]], ....., your_list[[length of your_list]])
。
your_list
包含大小相等的向量。NULL
长度为0,因此应该失败。
您可以使用该plyr
包。例如,表单的嵌套列表
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
现在的长度为4,并且每个列表中都l
包含另一个长度为3的列表。现在您可以运行
library (plyr)
df <- ldply (l, data.frame)
并应获得与答案@Marek和@nico相同的结果。
matrix
方法转换为字符。
data.frame(t(sapply(mylistlist,c)))
sapply
将其转换为矩阵。
data.frame
将矩阵转换为数据帧。
c
在这里扮演什么角色?列表数据的一个实例?哦,等等,c是连接函数吗?与@mnel的c用法混淆。我也同意@dchandler,在我的用例中,正确设置列名称是一个宝贵的需求。出色的解决方案。
?c
:Combine Values into a Vector or List
假设您的列表名为L
,
data.frame(Reduce(rbind, L))
data.frame(Reduce(rbind, list(c('col1','col2'))))
会很好地工作:产生一个包含2行1列的数据帧(我希望1行2列)
该软件包data.table
具有的rbindlist
超快实现功能do.call(rbind, list(...))
。
它可以采取的一个列表 lists
,data.frames
或data.tables
作为输入。
library(data.table)
ll <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
DT <- rbindlist(ll)
这会传回的data.table
继承data.frame
。
如果您真的想转换回data.frame,请使用as.data.frame(DT)
setDF
现在允许通过引用返回到data.frame。
所述tibble
封装具有一个功能enframe()
,解决了此问题,通过强迫嵌套list
对象嵌套tibble
(“整洁”的数据帧)的对象。这是R for Data Science的一个简短示例:
x <- list(
a = 1:5,
b = 3:4,
c = 5:6
)
df <- enframe(x)
df
#> # A tibble: 3 × 2
#> name value
#> <chr> <list>
#> 1 a <int [5]>
#> 2 b <int [2]>
#> 3 c <int [2]>
由于列表中有多个嵌套l
,因此您可以使用unlist(recursive = FALSE)
删除不必要的嵌套,以获取单个层次结构列表,然后传递给enframe()
。我tidyr::unnest()
通常将输出取消嵌套到单个级别的“整洁”数据框中,该数据框有您的两列(一列用于组name
,一列用于与组的观察value
)。如果要使列变宽,则可以使用add_column()
该列来添加,只需将值的顺序重复132次即可。然后就是spread()
值。
library(tidyverse)
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
l_tib <- l %>%
unlist(recursive = FALSE) %>%
enframe() %>%
unnest()
l_tib
#> # A tibble: 2,640 x 2
#> name value
#> <int> <chr>
#> 1 1 d
#> 2 1 z
#> 3 1 l
#> 4 1 b
#> 5 1 i
#> 6 1 j
#> 7 1 g
#> 8 1 w
#> 9 1 r
#> 10 1 p
#> # ... with 2,630 more rows
l_tib_spread <- l_tib %>%
add_column(index = rep(1:20, 132)) %>%
spread(key = index, value = value)
l_tib_spread
#> # A tibble: 132 x 21
#> name `1` `2` `3` `4` `5` `6` `7` `8` `9` `10` `11`
#> * <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1 d z l b i j g w r p y
#> 2 2 w s h r i k d u a f j
#> 3 3 r v q s m u j p f a i
#> 4 4 o y x n p i f m h l t
#> 5 5 p w v d k a l r j q n
#> 6 6 i k w o c n m b v e q
#> 7 7 c d m i u o e z v g p
#> 8 8 f s e o p n k x c z h
#> 9 9 d g o h x i c y t f j
#> 10 10 y r f k d o b u i x s
#> # ... with 122 more rows, and 9 more variables: `12` <chr>, `13` <chr>,
#> # `14` <chr>, `15` <chr>, `16` <chr>, `17` <chr>, `18` <chr>,
#> # `19` <chr>, `20` <chr>
根据列表的结构,有些tidyverse
选项可以很好地用于不等长列表:
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5)
, c = list(var.1 = 7, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = NA))
df <- dplyr::bind_rows(l)
df <- purrr::map_df(l, dplyr::bind_rows)
df <- purrr::map_df(l, ~.x)
# all create the same data frame:
# A tibble: 4 x 3
var.1 var.2 var.3
<dbl> <dbl> <dbl>
1 1 2 3
2 4 5 NA
3 7 NA 9
4 10 11 NA
您还可以混合矢量和数据帧:
library(dplyr)
bind_rows(
list(a = 1, b = 2),
data_frame(a = 3:4, b = 5:6),
c(a = 7)
)
# A tibble: 4 x 2
a b
<dbl> <dbl>
1 1 2
2 3 5
3 4 6
4 7 NA
X2
收到的错误消息是错误:无法将列从整数转换为字符
Reshape2产生的输出与上面的plyr示例相同:
library(reshape2)
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
l <- melt(l)
dcast(l, L1 ~ L2)
产量:
L1 var.1 var.2 var.3
1 a 1 2 3
2 b 4 5 6
3 c 7 8 9
4 d 10 11 12
如果您几乎没有像素,则可以用 recast()在1行中完成所有操作。
对于具有3个或更多级别的深度嵌套列表的一般情况,例如从嵌套JSON获得的列表:
{
"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()
再扩大到一个整洁的数据集,其中每个变量形成一个列,每个观察值形成一个行:
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
更多答案以及答案的时间安排: 将列表转换为数据帧的最有效方法是什么?
最快的方法是不产生具有列表的数据框,而不是产生列的矢量的数据框是(根据Martin Morgan的回答):
l <- list(list(col1="a",col2=1),list(col1="b",col2=2))
f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE)
as.data.frame(Map(f(l), names(l[[1]])))
有时,您的数据可能是相同长度的向量列表的列表。
lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )
(内部向量也可以是列表,但是我正在简化以使其更易于阅读)。
然后,您可以进行以下修改。请记住,您可以一次取消列出一个级别:
lov = unlist(lolov, recursive = FALSE )
> lov
[[1]]
[1] 1 2 3
[[2]]
[1] 4 5 6
[[3]]
[1] 7 8 9
[[4]]
[1] 10 11 12
[[5]]
[1] 13 14 15
现在,使用其他答案中提到的您喜欢的方法:
library(plyr)
>ldply(lov)
V1 V2 V3
1 1 2 3
2 4 5 6
3 7 8 9
4 10 11 12
5 13 14 15
这终于对我有用:
do.call("rbind", lapply(S1, as.data.frame))
对于使用purrr
一系列解决方案的并行(多核,多会话等)解决方案,请使用:
library (furrr)
plan(multisession) # see below to see which other plan() is the more efficient
myTibble <- future_map_dfc(l, ~.x)
l
清单在哪里。
要确定最有效的基准,plan()
可以使用:
library(tictoc)
plan(sequential) # reference time
# plan(multisession) # benchamark plan() goes here. See ?plan().
tic()
myTibble <- future_map_dfc(l, ~.x)
toc()
以下简单命令对我有用:
myDf <- as.data.frame(myList)
参考(Quora回答)
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6))
> myList
$a
[1] 1 2 3
$b
[1] 4 5 6
> myDf <- as.data.frame(myList)
a b
1 1 4
2 2 5
3 3 6
> class(myDf)
[1] "data.frame"
但是,如果将列表转换为数据框的方式不明显,则将失败:
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6, 7))
> myDf <- as.data.frame(myList)
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, :
arguments imply differing number of rows: 3, 4
注意:答案是针对问题的标题,可能会跳过问题的一些详细信息
一种简单(但可能不是最快)的方法是使用base r,因为数据帧只是等长向量的列表。因此,您的输入列表和30 x 132 data.frame之间的转换将是:
df <- data.frame(l)
从那里,我们可以将其转置为132 x 30矩阵,并将其转换回数据帧:
new_df <- data.frame(t(df))
作为单线:
new_df <- data.frame(t(data.frame(l)))
行名看起来很烦人,但是您总是可以使用
rownames(new_df) <- 1:nrow(new_df)
如何将map_
函数与for
循环一起使用?这是我的解决方案:
list_to_df <- function(list_to_convert) {
tmp_data_frame <- data.frame()
for (i in 1:length(list_to_convert)) {
tmp <- map_dfr(list_to_convert[[i]], data.frame)
tmp_data_frame <- rbind(tmp_data_frame, tmp)
}
print(tmp_data_frame)
}
其中,map_dfr
将每个列表元素的成data.frame,然后rbind
工会通通。
就您而言,我想应该是:
converted_list <- list_to_df(l)