R - список к фрейму данных - PullRequest
451 голосов
/ 19 ноября 2010

У меня есть вложенный список данных.Его длина равна 132, а каждый элемент представляет собой список длиной 20. Существует ли быстрый способ преобразования этой структуры во фрейм данных, содержащий 132 строки и 20 столбцов данных?Вот некоторые примеры данных для работы:

l <- replicate(
  132,
  list(sample(letters, 20)),
  simplify = FALSE
)

Ответы [ 19 ]

413 голосов
/ 19 ноября 2010

С rbind

do.call(rbind.data.frame, your_list)

Редактировать: Предыдущая версия возвращает data.frame из list вместо векторов (как указал @IanSudbery в комментариях).

322 голосов
/ 19 ноября 2010

Предполагая, что ваш список списков называется 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)
121 голосов
/ 19 ноября 2010

Вы можете использовать пакет 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.

86 голосов
/ 19 ноября 2010

data.frame(t(sapply(mylistlist,c)))

sapply преобразует его в матрицу. data.frame преобразует матрицу в кадр данных.

59 голосов
/ 24 марта 2014

предположим, что ваш список называется L,

data.frame(Reduce(rbind, L))
51 голосов
/ 26 марта 2013

Пакет 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)

29 голосов
/ 09 апреля 2017

В пакете tibble есть функция enframe(), которая решает эту проблему путем принудительной установки вложенных объектов list во вложенные объекты tibble ("аккуратный" фрейм данных). Вот краткий пример из R для 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>
16 голосов
/ 16 мая 2013

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 ().

10 голосов
/ 11 июля 2018

В зависимости от структуры ваших списков существуют некоторые опции 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
9 голосов
/ 30 мая 2018

В этом методе используется пакет tidyverse ( purrr ).

Список:

x <- as.list(mtcars)

Преобразование его во фрейм данных (a tibbleболее конкретно):

library(purrr)
map_df(x, ~.x)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...