web-dev-qa-db-ja.com

ベクトルのリストをデータフレームに変換する

ベクトルのリスト(本質的には多次元配列)をデータフレームに変換しようとしていますが、試行するたびに予期しない結果が得られます。

私の目的は、空のリストをインスタンス化し、そのループの繰り返しに関する情報を含むベクトルを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で強制されることさえありません(これは回避するのにひどい作業になると思いますが、試しました)。

誰でも洞察を得ましたか?

25
Nick

次を使用できます。

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

私が知っている最速で最も効率的な方法は、_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
_
8
Giuseppe

また、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

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

このコードは、各ベクトルをリストに効率的に変換し、結果を行ごとに共通のデータフレームに連結します。

4
Artem Sokolov