web-dev-qa-db-ja.com

R - データフレームへのリスト

ネストしたデータのリストがあります。その長さは132で、各項目は長さ20のリストです。この構造を132行20列のデータを持つデータフレームに変換する quick の方法はありますか。

これにはいくつかのサンプルデータがあります。

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

リストのリストがlと呼ばれるとします。

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

上の例はすべての文字列を因子に変換します。これを避けるためにdata.frame()呼び出しにパラメータを追加することができます。

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

rbindとは

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

編集:以前のバージョンでは(@IanSudberyがコメントで指摘したように)ベクトルの代わりにlistdata.frameを返します。

408
Marek

plyrパッケージを使うことができます。例えば、フォームのネストしたリスト

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

長さは4で、lの各リストには長さ3の別のリストが含まれています。これで実行できます。

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

@Marekと@nicoの答えと同じ結果になるはずです。

120
mropa

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

sapplyはそれを行列に変換します。 data.frameは行列をデータフレームに変換します。

85
Alex Brown

あなたのリストがLと呼ばれているとします。

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

パッケージdata.tableは、do.call(rbind, list(...))の超高速実装である関数rbindlistを持っています。

入力としてlistsdata.framesまたはdata.tablesのリストを取ることができます。

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)

これはdata.tableから継承したdata.frameを返します。

本当に に変換してdata.frameに戻したい場合はas.data.frame(DT)を使用してください。

51
mnel

tibbleパッケージには、ネストしたlistオブジェクトをネストしたtibble( "tidy"データフレーム)オブジェクトに強制変換することでこの問題を解決する関数enframe()があります。データ科学のための Rからの簡単な例はここにあります

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

リストにはいくつかのネストlがあるので、unlist(recursive = FALSE)を使って不要なネストを削除して単一の階層リストだけを取得してからenframe()に渡すことができます。 tidyr::unnest()を使用して、出力を単一レベルの「きちんとした」データフレームにネスト解除します。これには、2つの列(1つはグループname用、もう1つはグループvalue付きの観測)があります。幅の広い列が必要な場合は、add_column()を使用して列を追加できます。これは、値の順序を132回繰り返すだけです。それから値をspread()するだけです。


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

Reshape2は、上記のplyrの例と同じ出力を生成します。

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)

収量:

  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

あなたがほとんどピクセルを使い果たしていたなら、あなたはcouldこれを1行w/recast()でやってください。

16
Jack Ryan

リストの構造によっては、長さが異なるリストでうまく機能するtidyverseオプションがいくつかあります。

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

ベクトルとデータフレームを混在させることもできます。

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

@ Marekの答えを拡張する:文字列が要素に変換されて効率が問題にならないようにしたい場合

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

ネストされたJSONから取得されるもののような、深くネストされたリスト3つ以上のレベルを持つの一般的なケースでは:

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

最初にネストしたリストを縦長の形式に変換するmelt()のアプローチを考えてください。

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

続いてdcast()が続き、それぞれの変数が1つの列を形成し、それぞれの観測値が1つの行を形成する整然としたデータセットに再び広がります。

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

この質問に対する答えの中でのタイミングと一緒に、より多くの答え: データフレームとしてリストをキャストするための最も効率的な方法は何ですか?

最も簡単な方法は、列のベクトルではなくリストを含むデータフレームを生成しないことです(Martin Morganの回答から)。

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

このメソッドはtidyverseパッケージ( purrr )を使います。

リスト:

x <- as.list(mtcars)

それをデータフレーム(より具体的にはtibble)に変換します。

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

時々あなたのデータは同じ長さのベクトルのリストのリストであるかもしれません。

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

(内側のベクトルもリストにすることができますが、これを読みやすくするために簡略化しています)。

その後、次のように修正することができます。一度に1レベルずつリストを解除することができます。

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

今すぐ他の答えで述べたあなたの好きな方法を使ってください:

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

これがついに私のために働いたものです:

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

4
Amit Kohli

purrrファミリーのソリューションを使用した並列(マルチコア、マルチセッションなど)ソリューションの場合は、以下を使用してください。

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

lはリストです。

最も効率的なplan()をベンチマークするためにあなたは使うことができます:

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

次の簡単なコマンドは私のために働きました:

myDf <- as.data.frame(myList)

問い合わせ先( Quora answer

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

しかし、リストをデータフレームに変換する方法が明確でない場合、これは失敗します。

> 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