ベクトルのリスト(本質的には多次元配列)をデータフレームに変換しようとしていますが、試行するたびに予期しない結果が得られます。
私の目的は、空のリストをインスタンス化し、そのループの繰り返しに関する情報を含むベクトルをforループに挿入し、終了後にデータフレームに変換することです。
> vectorList <- list()
> for(i in 1:5){
+ vectorList[[i]] <- c("number" = i, "square root" = sqrt(i))
+ }
> vectorList
出力:
> [[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
今、私はこれを2つの変数の5つの観測値を持つデータフレームにしたいが、「vectorList」からデータフレームを作成しようとしています
numbers <- data.frame(vectorList)
5つの変数を2回観測します。
奇妙なことに、reshape2で強制されることさえありません(これは回避するのにひどい作業になると思いますが、試しました)。
誰でも洞察を得ましたか?
次を使用できます。
as.data.frame(do.call(rbind, vectorList))
または:
library(data.table)
rbindlist(lapply(vectorList, as.data.frame.list))
または:
library(dplyr)
bind_rows(lapply(vectorList, as.data.frame.list))
私が知っている最速で最も効率的な方法は、_data.table::transpose
_関数を使用することです(ベクトルの長さが低次元の場合):
as.data.frame(data.table::transpose(vectorList), col.names = names(vectorList[[1]]))
ただし、_data.table::transpose
_によって列名が削除されるため、列名を手動で設定する必要があります。列名を削除しない_purrr::transpose
_関数もありますが、速度が遅いようです。他のユーザーの提案を含む小さなベンチマークの下:
_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
_
また、Reduce
:
Reduce(rbind, vectorList)
# number square root
# init 1 1.000000
# 2 1.414214
# 3 1.732051
# 4 2.000000
# 5 2.236068
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
このコードは、各ベクトルをリストに効率的に変換し、結果を行ごとに共通のデータフレームに連結します。