R - list to data frame
我有一个嵌套的数据列表。 它的长度是132,每个项目都是长度为20的列表。是否有一种快速方法将此结构转换为具有132行和20列数据的数据框?
以下是一些要使用的示例数据:
1 2 3 4 5 | l <- replicate( 132, list(sample(letters, 20)), simplify = FALSE ) |
用
1 | do.call(rbind.data.frame, your_list) |
编辑:以前的版本返回
假设您的列表列表名为
1 | df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=T)) |
以上将所有字符列转换为因子,为避免这种情况,您可以向data.frame()调用添加一个参数:
1 | df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE) |
您可以使用
例如,表单的嵌套列表
1 2 3 4 5 | 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,
现在你可以跑了
1 2 | library (plyr) df <- ldply (l, data.frame) |
并且应该得到与答案@Marek和@nico相同的结果。
假设您的列表名为
1 | data.frame(Reduce(rbind, L)) |
包
它可以采用
1 2 3 4 5 6 7 8 | 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.frame,请使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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]> |
由于列表中有多个嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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> |
Reshape2产生的输出与上面的plyr示例相同:
1 2 3 4 5 6 7 8 | 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) |
收益率:
1 2 3 4 5 | 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 |
如果你几乎没有像素,你可以在1行w / recast()中完成这一切。
根据列表的结构,有一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
您还可以混合矢量和数据框:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
延伸@ Marek的答案:如果你想避免字符串被转化为因素和效率不是一个值得关注的尝试
1 | do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE)) |
此方法使用
列表:
1 | x <- as.list(mtcars) |
将其转换为数据框(更具体地说,
1 2 | library(purrr) map_df(x, ~.x) |
对于具有3个或更多级别的深层嵌套列表的一般情况,例如从嵌套JSON获得的级别:
1 2 3 4 5 6 7 8 | { "2015": { "spain": {"population": 43,"GNP": 9}, "sweden": {"population": 7,"GNP": 6}}, "2016": { "spain": {"population": 45,"GNP": 10}, "sweden": {"population": 9,"GNP": 8}} } |
考虑
1 2 3 4 5 6 7 8 9 10 11 | 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 |
然后是
1 2 3 4 5 6 7 8 | 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的答案):
1 2 3 | 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]]))) |
有时您的数据可能是相同长度的矢量列表的列表。
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)) ) |
(内部向量也可以是列表,但我正在简化以使其更容易阅读)。
然后您可以进行以下修改。请记住,您可以一次取消一个级别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
现在使用其他答案中提到的您最喜欢的方法:
1 2 3 4 5 6 7 8 | 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 |
1 2 3 | l <- replicate(10,list(sample(letters, 20))) a <-lapply(l[1:10],data.frame) do.call("cbind", a) |
这最终对我有用:
对于使用
1 2 3 | library (furrr) plan(multisession) # see below to see which other plan() is the more efficient myTibble <- future_map_dfc(l, ~.x) |
其中
要对最有效的
1 2 3 4 5 6 | library(tictoc) plan(sequential) # reference time # plan(multisession) # benchamark plan() goes here. See ?plan(). tic() myTibble <- future_map_dfc(l, ~.x) toc() |
以下简单命令对我有用:
1 | myDf <- as.data.frame(myList) |
参考(Quora答案)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > 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" |
但如果将列表转换为数据框并不明显,则会失败:
1 2 3 4 | > 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看起来很烦人,但你可以随时重命名