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

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

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

Ответы [ 19 ]

9 голосов
/ 06 ноября 2016

Для общего случая глубоко вложенных списков с 3 или более уровнями , подобных тем, которые получены из вложенного JSON:

{
"2015": {
  "spain": {"population": 43, "GNP": 9},
  "sweden": {"population": 7, "GNP": 6}},
"2016": {
  "spain": {"population": 45, "GNP": 10},
  "sweden": {"population": 9, "GNP": 8}}
}

рассмотрим подход melt() для преобразованиясначала вложенный список в высокий формат:

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

, затем dcast(), а затем снова в широкий массив данных, в котором каждая переменная образует столбец, а каждое наблюдение - строку:

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
9 голосов
/ 28 апреля 2015

Расширение ответа @ Marek: если вы хотите избежать превращения строк в факторы, а эффективность не является проблемой, попробуйте

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
8 голосов
/ 15 марта 2013

Дополнительные ответы, а также сроки в ответе на этот вопрос: Какой самый эффективный способ создать список как фрейм данных?

Самый быстрый способ, который не создает информационный фрейм со списками, а не векторами для столбцов, кажется (из ответа Мартина Моргана):

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]])))
7 голосов
/ 25 октября 2016

Иногда ваши данные могут быть списком векторов одинаковой длины.

lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )

(Внутренние векторы также могут быть списками, но я упрощаю, чтобы их было легче читать)

Тогда вы можете сделать следующую модификацию. Помните, что вы можете удалить один уровень за раз:

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

Теперь используйте ваш любимый метод, упомянутый в других ответах:

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
4 голосов
/ 20 апреля 2016
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
4 голосов
/ 11 декабря 2015

Вот что у меня наконец получилось:

do.call("rbind", lapply(S1, as.data.frame))

2 голосов
/ 23 апреля 2019

Для параллельного (многоядерного, мультисессионного и т. Д.) Решения, использующего семейство решений purrr, используйте:

library (furrr)
plan(multisession) # see below to see which other plan() is the more efficient
myTibble <- future_map_dfc(l, ~.x)

Где l - список.

Для сравнениянаиболее эффективный plan() вы можете использовать:

library(tictoc)
plan(sequential) # reference time
# plan(multisession) # benchamark plan() goes here. See ?plan().
tic()
myTibble <- future_map_dfc(l, ~.x)
toc()
0 голосов
/ 11 апреля 2019

У меня сработала следующая простая команда:

myDf <- as.data.frame(myList)

Ссылка ( Quora answer )

> 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"

Но это не получится, если неясно, как преобразовать список во фрейм данных:

> 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
0 голосов
/ 22 декабря 2018

Короткий (но, возможно, не самый быстрый) способ сделать это - использовать базу 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(new_df) <- 1:nrow(new_df)

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