wake-up-neo.com

Konvertieren Sie die Liste der Vektoren in einen Datenrahmen

Ich versuche, eine Liste von Vektoren (im Wesentlichen ein mehrdimensionales Array) in einen Datenrahmen zu konvertieren, aber jedes Mal, wenn ich es versuche, bekomme ich unerwartete Ergebnisse.

Mein Ziel ist es, eine leere Liste zu instantiieren, sie in einer for-Schleife mit Vektoren zu füllen, die Informationen zu dieser Iteration der Schleife enthalten, und sie anschließend in einen Datenrahmen zu konvertieren, nachdem sie abgeschlossen ist.

> vectorList <- list()
> for(i in  1:5){
+     vectorList[[i]] <- c("number" = i, "square root" = sqrt(i))
+ }
> vectorList

Ausgänge:

> [[1]]
>      number square root 
>           1           1 
> 
> [[2]]
>      number square root 
>    2.000000    1.414214 
> 
> [[3]]
>      number square root 
>    3.000000    1.732051 
> 
> [[4]]
>      number square root 
>           4           2 
> 
> [[5]]
>      number square root 
>    5.000000    2.236068

Jetzt möchte ich, dass dies ein Datenrahmen mit 5 Beobachtungen von 2 Variablen wird, aber versucht, einen Datenrahmen aus 'vectorList' zu erstellen.

numbers <- data.frame(vectorList)

führt zu 2 Beobachtungen von 5 Variablen.

Seltsamerweise wird es nicht einmal mit reshape2 gezwungen (was ich weiß, wäre eine schreckliche Arbeit, aber ich habe es versucht).

Hat jemand einen Einblick?

17
Nick

Sie können verwenden:

as.data.frame(do.call(rbind, vectorList))

Oder:

library(data.table)
rbindlist(lapply(vectorList, as.data.frame.list))

Oder:

library(dplyr)
bind_rows(lapply(vectorList, as.data.frame.list))
21
h3rm4n

Der schnellste und effizienteste Weg, den ich kenne, ist die Verwendung der Funktion data.table::transpose (Wenn die Länge Ihres Vektors niedrigdimensional ist):

as.data.frame(data.table::transpose(vectorList), col.names = names(vectorList[[1]]))

Sie müssen die Spaltennamen jedoch manuell festlegen, da data.table::transpose Sie entfernt. Es gibt auch eine purrr::transpose - Funktion, die die Spaltennamen nicht entfernt, aber langsamer zu sein scheint. Nachfolgend eine kleine Benchmark mit den Vorschlägen der anderen Benutzer:

vectorList = lapply(1:1000, function(i) (c("number" = i, "square root" = sqrt(i))))
bench = microbenchmark::microbenchmark(
  dplyr = dplyr::bind_rows(lapply(vectorList, as.data.frame.list)),
  rbindlist = data.table::rbindlist(lapply(vectorList, as.data.frame.list)),
  Reduce = Reduce(rbind, vectorList),
  transpose_datatable = as.data.frame(data.table::transpose(vectorList), col.names = names(vectorList[[1]])),
  transpose_purrr = data.table::as.data.table(purrr::transpose(vectorList)),
  do.call = as.data.frame(do.call(rbind, vectorList)),
  times = 10)
bench
# Unit: microseconds
#                 expr        min         lq        mean      median         uq        max neval cld
#                dplyr 286963.036 292850.136 320345.1137 310159.7380 341654.619 385399.851    10   b
#            rbindlist 285830.750 289935.336 306120.7257 309581.1895 318131.031 324217.413    10   b
#               Reduce   8573.474   9073.649  12114.5559   9632.1120  11153.511  33446.353    10  a 
#  transpose_datatable    372.572    424.165    500.8845    479.4990    532.076    701.822    10  a 
#      transpose_purrr    539.953    590.365    672.9531    671.1025    718.757    911.343    10  a 
#              do.call    452.915    537.591    562.9144    570.0825    592.334    641.958    10  a 

# now use bigger list and disregard the slowest
vectorList = lapply(1:100000, function(i) (c("number" = i, "square root" = sqrt(i))))
bench.big = microbenchmark::microbenchmark(
  transpose_datatable = as.data.frame(data.table::transpose(vectorList), col.names = names(vectorList[[1]])),
  transpose_purrr = data.table::as.data.table(purrr::transpose(vectorList)),
  do.call = as.data.frame(do.call(rbind, vectorList)),
  times = 10)
bench.big
# Unit: milliseconds
#                 expr       min        lq       mean     median         uq       max neval cld
#  transpose_datatable  3.470901   4.59531   4.551515   4.708932   4.873755   4.91235    10 a  
#      transpose_purrr 61.007574  62.06936  68.634732  65.949067  67.477948  97.39748    10  b 
#              do.call 97.680252 102.04674 115.669540 104.983596 138.193644 151.30886    10   c
8
Giuseppe

Auch Reduce:

Reduce(rbind, vectorList)

    # number square root
# init      1    1.000000
          # 2    1.414214
          # 3    1.732051
          # 4    2.000000
          # 5    2.236068
6
989

Eine alternative Lösung mit purrr:

purrr::map_dfr( vectorList, as.list )
# # A tibble: 5 x 2
#   number `square root`
#    <dbl>         <dbl>
# 1      1          1   
# 2      2          1.41
# 3      3          1.73
# 4      4          2   
# 5      5          2.24

Der Code konvertiert jeden Vektor effektiv in eine Liste und verkettet die Ergebnisse zeilenweise zu einem gemeinsamen Datenrahmen.

1
Artem Sokolov