我有一个嵌套的数据列表。它的长度是132,每一项是一个长度为20的列表。是否有一种快速的方法可以将这种结构转换为具有132行和20列数据的数据帧?
下面是一些示例数据:
l <- replicate(
132,
as.list(sample(letters, 20)),
simplify = FALSE
)
我有一个嵌套的数据列表。它的长度是132,每一项是一个长度为20的列表。是否有一种快速的方法可以将这种结构转换为具有132行和20列数据的数据帧?
下面是一些示例数据:
l <- replicate(
132,
as.list(sample(letters, 20)),
simplify = FALSE
)
当前回答
该方法使用一个tidyverse包(purrr)。
列表:
x <- as.list(mtcars)
将其转换为数据帧(更具体地说是tibble):
library(purrr)
map_df(x, ~.x)
编辑时间:2021年5月30日
这实际上可以通过dplyr中的bind_rows()函数实现。
x <- as.list(mtcars)
dplyr::bind_rows(x)
A tibble: 32 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
# ... with 22 more rows
其他回答
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
如果你几乎没有像素,你可以在一行w/ recast()中完成这一切。
tibble包有一个函数enframe(),它通过将嵌套的列表对象强制转换为嵌套的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]>
Since you have several nests in your list, l, you can use the unlist(recursive = FALSE) to remove unnecessary nesting to get just a single hierarchical list and then pass to enframe(). I use tidyr::unnest() to unnest the output into a single level "tidy" data frame, which has your two columns (one for the group name and one for the observations with the groups value). If you want columns that make wide, you can add a column using add_column() that just repeats the order of the values 132 times. Then just spread() the values.
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>
2020年7月更新:
stringsAsFactors参数的默认值现在是default.stringsAsFactors(),它的默认值是FALSE。
假设你的列表的列表叫做l:
df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=TRUE))
上面的代码会将所有的字符列转换为因子,为了避免这种情况,你可以在data.frame()调用中添加一个参数:
df <- data.frame(matrix(unlist(l), nrow=132, byrow=TRUE),stringsAsFactors=FALSE)
你可以使用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相同的结果。
如何使用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)
}
return(tmp_data_frame)
}
其中map_dfr将每个列表元素转换为data.frame,然后rbind将它们合并。
在你的情况下,我猜应该是:
converted_list <- list_to_df(l)