R:将列表转换为data.frame

时间:2018-06-06 16:09:56

标签: r list dataframe

mylist <- list(NULL, structure(list(Gender = structure(1L, .Label = "Female", class = "factor"), 
  ID = structure(1L, .Label = "1", class = "factor"), Class = structure(1L, .Label = "A", class = "factor"), 
  Score1 = 21.6, Score2 = 39.61, Score3 = 8.85, 
  Score4 = 13.66, Score5 = 2.64999999999999, Score6 = 6.94736842105265), .Names = c("Gender", 
  "ID", "Class", "Score1", "Score2", "Score3", 
  "Score4", "Score5", "Score6"), row.names = c(NA, -1L
  ), class = "data.frame"), list(structure(list(Gender = structure(1:2, .Label = c("Female", 
  "Male"), class = "factor"), ID = structure(c(1L, 1L), .Label = "2", class = "factor"), 
  Class = structure(c(1L, 1L), .Label = "A", class = "factor"), 
  Score1 = c(25.58, 18.31), Score2 = c(55.01, 
  36.28), Score3 = c(1.66, 2.13), Score4 = c(3.6, 
  4.24), Score5 = c(15.2727272727273, 8.57142857142858), Score6 = c(15.5833333333334, 
  8.4545454545455)), .Names = c("Gender", "ID", "Class", 
  "Score1", "Score2", "Score3", "Score4", 
  "Score5", "Score6"), row.names = c(NA, -2L), class = "data.frame"), 
  structure(list(Gender = structure(1:2, .Label = c("Female", 
  "Male"), class = "factor"), ID = structure(c(1L, 1L), .Label = "3", class = "factor"), 
  Class = structure(c(1L, 1L), .Label = "A", class = "factor"), 
  Score1 = c(27.16, 14.67), Score2 = c(58.39, 
  29.07), Score3 = c(1.66, 2.13), Score4 = c(3.6, 
  4.24), Score5 = c(16.2727272727273, 6.85714285714286), 
  Score6 = c(16.5833333333333, 6.81818181818185)), .Names = c("Gender", 
  "ID", "Class", "Score1", "Score2", 
  "Score3", "Score4", "Score5", "Score6"), row.names = c(NA,-2L), class = "data.frame")))

我有一个类似的列表:

> mylist
[[1]]
NULL

[[2]]
  Gender ID Class Score1 Score2 Score3 Score4 Score5   Score6
1 Female  1     A   21.6  39.61   8.85  13.66   2.65 6.947368

[[3]]
[[3]][[1]]
  Gender ID Class Score1 Score2 Score3 Score4    Score5    Score6
1 Female  2     A  25.58  55.01   1.66   3.60 15.272727 15.583333
2   Male  2     A  18.31  36.28   2.13   4.24  8.571429  8.454545

[[3]][[2]]
  Gender ID Class Score1 Score2 Score3 Score4    Score5    Score6
1 Female  3     A  27.16  58.39   1.66   3.60 16.272727 16.583333
2   Male  3     A  14.67  29.07   2.13   4.24  6.857143  6.818182

其中一些元素是NULL,而其他元素可以有多个子元素,例如第三个元素有子元素[[1]][[2]]

我想将这些列表元素组合成一个看起来像这样的data.frame(为方便起见,我省略了Score2到Score6列的内容):

  Gender ID Class Score1 Score2 ... Score6
1 Female  1     A  21.60     
2 Female  2     A  25.58    
3   Male  2     A  18.31    
4 Female  3     A  27.16    
5   Male  3     A  14.67    

我尝试过以下但却出错了

> tab <- unlist(mylist, recursive = FALSE)
> df <- do.call("rbind", tab)
Warning in `[<-.factor`(`*tmp*`, ri, value = 1L) :
  invalid factor level, NA generated
Warning in `[<-.factor`(`*tmp*`, ri, value = 1L) :
  invalid factor level, NA generated
...

使用ldply无法正确处理最后一个元素

> ldply(mylist, data.frame)
  Gender ID Class Score1 Score2 Score3 Score4    Score5    Score6 Gender.1 ID.1 Class.1 Score1.1 Score2.1 Score3.1 Score4.1  Score5.1  Score6.1
1 Female  1     A  21.60  39.61   8.85  13.66  2.650000  6.947368     <NA> <NA>    <NA>       NA       NA       NA       NA        NA        NA
2 Female  2     A  25.58  55.01   1.66   3.60 15.272727 15.583333   Female    3       A    27.16    58.39     1.66     3.60 16.272727 16.583333
3   Male  2     A  18.31  36.28   2.13   4.24  8.571429  8.454545     Male    3       A    14.67    29.07     2.13     4.24  6.857143  6.818182

3 个答案:

答案 0 :(得分:5)

您可以使用几个tidyverse函数非常简单地执行此操作。 purrr::reduce允许您在列表或向量中应用函数,dplyr::bind_rows就像一个扩展的,更智能的rbind

请注意,就像我在评论中所说的那样,您会收到有关您使用因子向量绑定字符向量这一事实的警告,但这只是警告,而不是错误

purrr::reduce(mylist, dplyr::bind_rows)

#> Warning in bind_rows_(x, .id): binding character and factor vector,
#> coercing into character vector

...

#>   Gender ID Class Score1 Score2 Score3 Score4    Score5    Score6
#> 1 Female  1     A  21.60  39.61   8.85  13.66  2.650000  6.947368
#> 2 Female  2     A  25.58  55.01   1.66   3.60 15.272727 15.583333
#> 3   Male  2     A  18.31  36.28   2.13   4.24  8.571429  8.454545
#> 4 Female  3     A  27.16  58.39   1.66   3.60 16.272727 16.583333
#> 5   Male  3     A  14.67  29.07   2.13   4.24  6.857143  6.818182

答案 1 :(得分:2)

试试这个:

ll <- unlist(lapply(mylist, function(x) if(is.data.frame(x)) list(x) else x), recursive = FALSE)
do.call(rbind, ll)
  Gender ID Class Score1 Score2 Score3 Score4    Score5    Score6
1 Female  1     A  21.60  39.61   8.85  13.66  2.650000  6.947368
2 Female  2     A  25.58  55.01   1.66   3.60 15.272727 15.583333
3   Male  2     A  18.31  36.28   2.13   4.24  8.571429  8.454545
4 Female  3     A  27.16  58.39   1.66   3.60 16.272727 16.583333
5   Male  3     A  14.67  29.07   2.13   4.24  6.857143  6.818182

答案 2 :(得分:1)

我建议使用名为unlist的广义unlist_unless函数,其作用类似unlist,但有以下区别:

  • 它有一个predicate参数,用于保持一些子元素不变(如果安装了purrr,则支持公式表示法)
  • ...将参数传递给predicate
  • keep_null用于保留(默认)或删除NULL元素

unlist类似,它的参数recursiveuse.names的默认设置默认设置为TRUE,默认情况下默认设置为keep_null,它还包含TRUE参数默认设置为unlist_unless <- function(x, predicate = function(x) FALSE, ..., recursive = TRUE, use.names = TRUE, keep_null = TRUE){ if(inherits(predicate, "formula")) { if (requireNamespace("purrr")) predicate <- purrr::as_mapper(predicate) else stop("Package `purrr` needs to be installed to use formula notation") } unlist(lapply(x, function(y){ if(predicate(y, ...) || (keep_null && is.null(y))) list(y) else if (is.list(y) && recursive) unlist_unless(y, predicate = predicate, ..., keep_null=keep_null, use.names = use.names) else y}), recursive = FALSE, use.names = use.names) }

df <- head(iris)[1:3]
dfs<- list(df[1,],
             NULL,
             list(df[2,],
                  df[3,],
                  list(df[4,]),
                  NULL))

unlist_unless(dfs, is.data.frame)
# [[1]]
# Sepal.Length Sepal.Width Petal.Length
# 1          5.1         3.5          1.4
# 
# [[2]]
# NULL
# 
# [[3]]
# Sepal.Length Sepal.Width Petal.Length
# 2          4.9           3          1.4
# 
# [[4]]
# Sepal.Length Sepal.Width Petal.Length
# 3          4.7         3.2          1.3
# 
# [[5]]
# Sepal.Length Sepal.Width Petal.Length
# 4          4.6         3.1          1.5
# 
# [[6]]
# NULL

例子1:最简单

unlist_unless(dfs, is.data.frame, keep_null = FALSE)
# [[1]]
# Sepal.Length Sepal.Width Petal.Length
# 1          5.1         3.5          1.4
# 
# [[2]]
# Sepal.Length Sepal.Width Petal.Length
# 2          4.9           3          1.4
# 
# [[3]]
# Sepal.Length Sepal.Width Petal.Length
# 3          4.7         3.2          1.3
# 
# [[4]]
# Sepal.Length Sepal.Width Petal.Length
# 4          4.6         3.1          1.5

unlist_unless(dfs, is.data.frame, recursive = FALSE)
# [[1]]
# Sepal.Length Sepal.Width Petal.Length
# 1          5.1         3.5          1.4
# 
# [[2]]
# NULL
# 
# [[3]]
# Sepal.Length Sepal.Width Petal.Length
# 2          4.9           3          1.4
# 
# [[4]]
# Sepal.Length Sepal.Width Petal.Length
# 3          4.7         3.2          1.3
# 
# [[5]]
# [[5]][[1]]
# Sepal.Length Sepal.Width Petal.Length
# 4          4.6         3.1          1.5
# 
# 
# [[6]]
# NULL

examples2:keep_null = FALSE

bind_rows(dfs_new)

然后可以直接在结果上调用do.call(rbind, dfs_new)do.call(rbind,unlist_unless(dfs, is.data.frame)) # Sepal.Length Sepal.Width Petal.Length # 1 5.1 3.5 1.4 # 2 4.9 3.0 1.4 # 3 4.7 3.2 1.3 # 4 4.6 3.1 1.5 # or library(dplyr) unlist_unless(dfs, is.data.frame) %>% bind_rows # Sepal.Length Sepal.Width Petal.Length # 1 5.1 3.5 1.4 # 2 4.9 3.0 1.4 # 3 4.7 3.2 1.3 # 4 4.6 3.1 1.5

[System.Data.DataColumn[]]$myitems = ([System.Data.DataColumn]("col1"), 
                [System.Data.DataColumn]("col2"),  [System.Data.DataColumn]("col3"))