it-swarm.com.de

R - Liste zum Datenrahmen

Ich habe eine verschachtelte Liste von Daten. Ihre Länge beträgt 132 und jedes Element ist eine Liste mit der Länge 20. Gibt es eine schnelle Möglichkeit, diese Struktur in einen Datenrahmen mit 132 Zeilen und zu konvertieren? 20 Datenspalten?

Hier sind einige Beispieldaten, mit denen Sie arbeiten können:

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

Angenommen, Ihre Listenliste heißt l:

df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=T))

Das Obige konvertiert alle Zeichenspalten in Faktoren. Um dies zu vermeiden, können Sie dem Aufruf von data.frame () einen Parameter hinzufügen:

df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
333
nico

Mit rbind

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

Bearbeiten: Vorherige Version gibt data.frame von list anstelle von Vektoren zurück (wie @IanSudbery in Kommentaren ausgeführt hat).

420
Marek

Sie können das Paket plyr verwenden. Zum Beispiel eine verschachtelte Liste des Formulars

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

hat jetzt eine Länge von 4 und jede Liste in l enthält eine andere Liste der Länge 3. Jetzt können Sie ausführen

  library (plyr)
  df <- ldply (l, data.frame)

und sollte das gleiche Ergebnis wie in der Antwort @Marek und @nico erhalten.

123
mropa

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

sapply konvertiert es in eine Matrix. data.frame konvertiert die Matrix in einen Datenrahmen.

86
Alex Brown

angenommen, Ihre Liste heißt L,

data.frame(Reduce(rbind, L))
59
jdeng

Das Paket data.table hat die Funktion rbindlist, die eine superschnelle Implementierung von do.call(rbind, list(...)) ist.

Es kann eine Liste von lists, data.frames oder data.tables als Eingabe verwendet werden.

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)

Dies gibt einen data.table zurück, der von data.frame erbt.

Wenn Sie wirklich in ein data.frame konvertieren möchten, verwenden Sie as.data.frame(DT)

51
mnel

Das tibble -Paket verfügt über eine Funktion enframe(), die dieses Problem löst, indem verschachtelte list -Objekte in verschachtelte tibble -Objekte ("aufgeräumte" Datenrahmen) umgewandelt werden. Hier ist ein kurzes Beispiel von R fü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]>

Da Ihre Liste mehrere Verschachtelungen enthält (l), können Sie mit unlist(recursive = FALSE) unnötige Verschachtelungen entfernen, um nur eine einzige hierarchische Liste zu erhalten, und dann zu enframe() übergehen. Ich verwende tidyr::unnest(), um die Ausgabe in einen einstufigen "aufgeräumten" Datenrahmen zu unterteilen, der Ihre zwei Spalten enthält (eine für die Gruppe name und eine für die Beobachtungen mit den Gruppen value). . Wenn Sie Spalten mit einer Breite wünschen, können Sie mit add_column() eine Spalte hinzufügen, die die Reihenfolge der Werte 132-mal wiederholt. Dann nur noch spread() die Werte.


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>
29
Matt Dancho

Reshape2 liefert die gleiche Ausgabe wie das obige Plyr-Beispiel:

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)

ergibt:

  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

Wenn Sie fast keine Pixel mehr haben, können Sie könnte dies alles in einer Zeile mit recast () tun.

16
Jack Ryan

Abhängig von der Struktur Ihrer Listen gibt es einige tidyverse Optionen, die gut mit Listen mit ungleicher Länge funktionieren:

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

Sie können auch Vektoren und Datenrahmen mischen:

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
11
sbha

Diese Methode verwendet ein tidyverse -Paket (purrr).

Die Liste:

x <- as.list(mtcars)

Konvertieren in einen Datenrahmen (genauer gesagt tibble):

library(purrr)
map_df(x, ~.x)
9
SavedByJESUS

Erweiterung der Antwort von @ Marek: Wenn Sie vermeiden möchten, dass Zeichenfolgen zu Faktoren und Effizienz werden, sollten Sie es nicht versuchen

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
9
laubbas

Für den allgemeinen Fall tief verschachtelter Listen mit 3 oder mehr Ebenen wie diejenigen, die von einem verschachtelten JSON erhalten wurden:

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

betrachten Sie den Ansatz von melt(), um die verschachtelte Liste zuerst in ein großes Format zu konvertieren:

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

gefolgt von dcast(), um erneut einen aufgeräumten Datensatz zu erstellen, in dem jede Variable eine Spalte und jede Beobachtung eine Zeile bildet:

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
ecerulm

Weitere Antworten sowie Zeitangaben in der Antwort auf diese Frage: Wie kann eine Liste am effizientesten als Datenrahmen umgewandelt werden?

Der schnellste Weg, der keinen Datenrahmen mit Listen anstelle von Vektoren für Spalten erzeugt, scheint (nach Martin Morgans Antwort) zu sein:

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]])))
9
Ian Sudbery

Manchmal können Ihre Daten eine Liste von Listen von Vektoren gleicher Länge sein.

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

(Die inneren Vektoren könnten auch Listen sein, aber ich vereinfache dies, um das Lesen zu erleichtern).

Dann können Sie die folgende Änderung vornehmen. Denken Sie daran, dass Sie jeweils eine Ebene aufheben können:

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

Verwenden Sie nun Ihre Lieblingsmethode, die in den anderen Antworten erwähnt wird:

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
7
user36302
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
4
zhan2383

Das hat bei mir endlich geklappt:

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

4
Amit Kohli

Verwenden Sie für eine parallele Lösung (Multicore, Multisession usw.) mit der purrr -Lösungsfamilie:

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

Wobei l die Liste ist.

Zum Benchmarking der effizientesten plan() können Sie Folgendes verwenden:

library(tictoc)
plan(sequential) # reference time
# plan(multisession) # benchamark plan() goes here. See ?plan().
tic()
myTibble <- future_map_dfc(l, ~.x)
toc()
2
trevi

Der folgende einfache Befehl hat bei mir funktioniert:

myDf <- as.data.frame(myList)

Referenz ( Quora-Antwort )

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

Dies schlägt jedoch fehl, wenn nicht klar ist, wie die Liste in einen Datenrahmen konvertiert werden soll:

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