ネストしたデータのリストがあります。その長さは132で、各項目は長さ20のリストです。この構造を132行20列のデータを持つデータフレームに変換する quick の方法はありますか。
これにはいくつかのサンプルデータがあります。
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
リストのリストが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)
rbind
とは
do.call(rbind.data.frame, your_list)
編集:以前のバージョンでは(@IanSudberyがコメントで指摘したように)ベクトルの代わりにlist
のdata.frame
を返します。
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の答えと同じ結果になるはずです。
data.frame(t(sapply(mylistlist,c)))
sapply
はそれを行列に変換します。 data.frame
は行列をデータフレームに変換します。
あなたのリストがL
と呼ばれているとします。
data.frame(Reduce(rbind, L))
パッケージdata.table
は、do.call(rbind, list(...))
の超高速実装である関数rbindlist
を持っています。
入力としてlists
、data.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)
を使用してください。
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>
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()でやってください。
リストの構造によっては、長さが異なるリストでうまく機能する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
@ Marekの答えを拡張する:文字列が要素に変換されて効率が問題にならないようにしたい場合
do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
ネストされた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
この質問に対する答えの中でのタイミングと一緒に、より多くの答え: データフレームとしてリストをキャストするための最も効率的な方法は何ですか?
最も簡単な方法は、列のベクトルではなくリストを含むデータフレームを生成しないことです(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]])))
このメソッドはtidyverse
パッケージ( purrr )を使います。
リスト:
x <- as.list(mtcars)
それをデータフレーム(より具体的にはtibble
)に変換します。
library(purrr)
map_df(x, ~.x)
時々あなたのデータは同じ長さのベクトルのリストのリストであるかもしれません。
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
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
これがついに私のために働いたものです:
do.call("rbind", lapply(S1, as.data.frame))
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()
次の簡単なコマンドは私のために働きました:
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