ネストされたデータのリストがあります。その長さは132で、各項目は長さ20のリストです。この構造を、132行と20列のデータを持つデータフレームにすばやく変換する方法はありますか?
処理するサンプルデータを次に示します。
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
ネストされたデータのリストがあります。その長さは132で、各項目は長さ20のリストです。この構造を、132行と20列のデータを持つデータフレームにすばやく変換する方法はありますか?
処理するサンプルデータを次に示します。
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)
編集:前のバージョンのリターンdata.frame
のlist
代わりにベクトルのさん(@IanSudberyはコメントで指摘したように)。
rbind(your_list)
1x32リストマトリックスを返すのですか?
do.call
要素をyour_list
として引数に渡しますrbind
。と同等ですrbind(your_list[[1]], your_list[[2]], your_list[[3]], ....., your_list[[length of your_list]])
。
your_list
同じサイズのベクターが含まれている必要があります。NULL
長さが0なので、失敗するはずです。
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と同じ結果が得られるはずです。
matrix
アプローチによって特性に変換されます。
data.frame(t(sapply(mylistlist,c)))
sapply
それを行列に変換します。
data.frame
マトリックスをデータフレームに変換します。
c
ここで、リストのデータの1つのインスタンスとしてどのような役割を果たしますか?ああ待って、連結関数のcですよね?@mnelのcの使用法と混同される。また、@ dchandlerにも同意します。列名を正しく取得することは、私のユースケースでの貴重なニーズでした。素晴らしいソリューション。
?c
:Combine Values into a Vector or List
あなたのリストがと呼ばれていると仮定しL
、
data.frame(Reduce(rbind, L))
data.frame(Reduce(rbind, list(c('col1','col2'))))
します。2行1列のデータフレームを生成します(1行2列が必要です)
パッケージには、の超高速実装であるdata.table
関数rbindlist
がありdo.call(rbind, list(...))
ます。
のリスト 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)
setDF
参照によりdata.frameに戻ることができるようになりました。
tibble
パッケージには、機能を有しているenframe()
ネストされた強制することでこの問題を解決しlist
、入れ子にオブジェクトをtibble
(「整頓」のデータフレームを)オブジェクト。以下は、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つはグループ用、もう1つはグループname
での観測用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>
リストの構造に応じて、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
X2
を整数から文字に変換できません
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
ピクセルがほとんどなくなった場合は、recast()を使用してこれをすべて1行で実行できます。
この方法では、tidyverse
パッケージ(purrr)を。
リスト:
x <- as.list(mtcars)
データフレームに変換する(tibble
より具体的に):
library(purrr)
map_df(x, ~.x)
ネストされた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()
て、整然としたデータセットに再び拡大し、各変数が列を形成し、各観測値が行を形成します。
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]])))
データが同じ長さのベクトルのリストのリストである場合があります。
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
ソリューション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回答)
> 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
注:回答は質問のタイトルに向けられており、質問の一部の詳細がスキップされる場合があります
データフレームは等しい長さのベクトルのリストに過ぎないため、これを行う短い(ただし、おそらく最速ではない)方法は、ベースrを使用することです。したがって、入力リストと30 x 132のdata.frameの間の変換は次のようになります。
df <- data.frame(l)
そこから、132 x 30の行列に転置して、データフレームに戻すことができます。
new_df <- data.frame(t(df))
ワンライナーとして:
new_df <- data.frame(t(data.frame(l)))
行名は見るのがかなり面倒ですが、いつでも名前を変更できます
rownames(new_df) <- 1:nrow(new_df)
map_
関数をfor
ループと一緒に使用してみませんか?これが私の解決策です:
list_to_df <- function(list_to_convert) {
tmp_data_frame <- data.frame()
for (i in 1:length(list_to_convert)) {
tmp <- map_dfr(list_to_convert[[i]], data.frame)
tmp_data_frame <- rbind(tmp_data_frame, tmp)
}
print(tmp_data_frame)
}
map_dfr
各リスト要素をdata.frame に変換してから、rbind
それらをすべて結合します。
あなたの場合、私はそれがそうなると思います:
converted_list <- list_to_df(l)