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?
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))
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
Auch Reduce
:
Reduce(rbind, vectorList)
# number square root
# init 1 1.000000
# 2 1.414214
# 3 1.732051
# 4 2.000000
# 5 2.236068
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.