我有一个嵌套的数据列表,长度为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
)
使用rbind
do.call(rbind.data.frame, your_list)
编辑:先前版本返回list
的data.frame
而不是向量(正如@IanSudbery在评论中指出的)。
rbind(your_list)
却返回一个 1x32 的列表矩阵? - eykanaldo.call
将 your_list
中的元素作为参数传递给 rbind
函数。相当于执行 rbind(your_list[[1]], your_list[[2]], your_list[[3]], ....., your_list[[your_list长度]])
。 - Marekyour_list
包含相同大小的向量。NULL
长度为0,因此应该会失败。 - Marek2020年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)
names(df) <- names(unlist(l[1]))
。 - Chulesplyr
包。例如,一个形式为嵌套列表的数据: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
中每个列表都包含长度为3的另一个列表,因此l
现在的长度为4。
现在你可以运行。
library (plyr)
df <- ldply (l, data.frame)
并且应该获得与@Marek和@nico答案中相同的结果。
c
在这里扮演什么角色,是列表数据的一个实例吗?哦,等等,你是指连接函数中的 c 对吧?我对 @mnel 使用 c 的方式感到有些困惑。我也同意 @dchandler 的观点,在我的用例中,正确获取列名是非常重要的需求。这是一个绝妙的解决方案。 - jxramosL
,data.frame(Reduce(rbind, L))
data.frame(Reduce(rbind, list(c('col1','col2'))))
会产生一个2行1列的数据框(我预期是1行2列)。 - Nate Andersonreduce(L, rbind)
。这将输出一个单独的数据框,并假定列表中的每个数据框(L)都以相同的方式组织(即按相同顺序包含相同数量的列)。 - ESELIA包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。 - Franktibble
包有一个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
从整数转换为字符”。 - Jolin这种方法使用tidyverse
包(purrr)。
列表:
x <- as.list(mtcars)
将其转换为数据框(更具体地说,是 tibble
):
library(purrr)
map_df(x, ~.x)
可以使用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
如果你的像素快用完了,你可以使用recast()将所有内容都放在一行中。