2016-02-12 7 views
13

私は文字列を含むリストのリストを持っています。各サブリストの最初の文字列は、次の文字列が属するカテゴリを示します。私は、カテゴリのための1つの列とコンテンツのための1つの列を持つ(ロングフォーマットの)データフレームを取得したい。 は、どのように私はこのリストから、長い形式のデータフレームを取得することができます。リストから長形式のデータフレームを取得

mylist <- list(
    c("A","lorem","ipsum"), 
    c("B","sed", "eiusmod", "tempor" ,"inci"), 
    c("C","aliq", "ex", "ea")) 

> mylist 
[[1]] 
[1] "A"  "lorem" "ipsum" 

[[2]] 
[1] "B"  "sed"  "eiusmod" "tempor" "incidunt" 

[[3]] 
[1] "C"  "aliquid" "ex"  "ea" 

は、それは私がすでにカテゴリやコンテンツを区切りました。このデータフレーム

mydf <- data.frame(cate= c("A","A","B","B","B","B","C","C","C"), 
       cont= c("lorem","ipsum","sed", "eiusmod", "tempor","inci","aliq", "ex", "ea")) 

> mydf 
    cate cont 
1 A lorem 
2 A ipsum 
3 B  sed 
4 B eiusmod 
5 B tempor 
6 B incidunt 
7 C aliquid 
8 C  ex 
9 C  ea 

のようになります。

cate <- sapply(mylist, "[[",1) 
cont <- sapply(mylist, "[", -(1)) 

mydfを取得するにはどうすればよいですか?

答えて

8

listの要素に 'cont'と 'cape'という名前を付けてからstackを使用できます。

setNames(stack(setNames(cont, cate))[2:1], c('cate', 'cont')) 
# cate cont 
#1 A lorem 
#2 A ipsum 
#3 B  sed 
#4 B eiusmod 
#5 B tempor 
#6 B inci 
#7 C aliq 
#8 C  ex 
#9 C  ea 
10

repをOPの投稿に既に作成されている変数と組み合わせて使用​​することもできます。

dat <- data.frame(cat=rep(cate, lengths(cont)), 
        cont=unlist(cont)) 

だから、「最良」の答えであるかについて、いくつかの議論が(でも、私は疑う1、存在する場合)、ここでは100000のリストに基づいて、(ケースのパフォーマンスの問題で)いくつかのベンチマークですがあったとして、プロセスへのベクトル:

Unit: milliseconds 
    expr  min  lq  mean median  uq  max neval cld 
heroka 56.24516 67.98583 122.1209 82.35606 117.6017 391.8297 50 a 
    akrun 258.86939 283.10408 363.5425 331.50263 448.9134 578.1818 50 b 
ananda 47.72320 61.05269 132.2678 76.22913 218.8286 385.5709 50 a 

ベンチマークコードは、両方のソリューションは、それらを使用すると、変数catecontがすでに作成されていることを前提としています。

heroka <- function(){ 
data.frame(cat=rep(cate, lengths(cont)), cont=unlist(cont)) 
} 

akrun <- function(){ 
    setNames(stack(setNames(cont, cate))[2:1], c('cate', 'cont')) 
} 

ananda <- function(){ 
    setorder(melt(as.data.table(transpose(mylist)), 
       id.vars = "V1", na.rm = TRUE), V1, variable)[] 
} 


mylist <- replicate(100000,c(sample(LETTERS[1:10],1),sample(LETTERS[1:10],sample(5)))) 
cate <- sapply(mylist, "[[",1) 
cont <- sapply(mylist, "[", -(1)) 

tests <- microbenchmark(
    heroka = heroka(), 
    akrun=akrun(),ananda=ananda(), 
    times=50 
) 
13

分割は、作成したオブジェクトを元のリストを使用していない、あなたは次のことを試すことができます。

楽しみのため
library(data.table) 
setorder(melt(as.data.table(transpose(mylist)), 
       id.vars = "V1", na.rm = TRUE), V1, variable)[] 
# V1 variable value 
# 1: A  V2 lorem 
# 2: A  V3 ipsum 
# 3: B  V2  sed 
# 4: B  V3 eiusmod 
# 5: B  V4 tempor 
# 6: B  V5 inci 
# 7: C  V2 aliq 
# 8: C  V3  ex 
# 9: C  V4  ea 

、あなたはまた、次のいずれかを試すことができます


library(dplyr) 
library(tidyr) 

data_frame(id = seq_along(mylist), mylist) %>% 
    unnest %>% 
    group_by(id) %>% 
    mutate(ind = mylist[1]) %>% 
    slice(2:n()) 

library(purrr) 
data_frame(
    value = mylist %>% map(~ .x[-1]) %>% unlist, 
    ind = mylist %>% map(~ rep(.x[1], length(.x)-1)) %>% unlist 
) 

"purrr"にもtransposeという機能があります。つまり、 "data.table"もロードされている場合は、次のようなものを使用する必要があります。 data.table::transposeまたはpurrr::transpose(私が元の回答の場合のように)これらの機能を使用している場合。私はテストしていませんが、私の推測では、 "data.table"は依然として元のリストから最も早く始めるでしょう。

4

各項目のdata.frame`は、リストのサイズが大きくなるほど痛々しいほど遅くなるだろう `呼び出すlapply

do.call(rbind, lapply(mylist, function(x) data.frame(cate = x[1], cont = x[-1]))) 

# cate cont 
#1 A lorem 
#2 A ipsum 
#3 B  sed 
#4 B eiusmod 
#5 B tempor 
#6 B inci 
#7 C aliq 
#8 C  ex 
#9 C  ea 
+2

を使用してちょうど別のオプションを選択します。 – A5C1D2H2I1M1N2O1R2T1

関連する問題