2015-12-10 22 views
13

私はこのようになりますデータフレームを平らにするために最善の「Rの道」を見つけたい:ソースデータフレームを生成するリストを含むRデータフレームをフラット化する方法は?

CAT COUNT1 COUNT2 COUNT3 TREAT1 TREAT2 TREAT3 
    A 1  2  3  Treat-a Treat-b NA 
    B 4  5  NA  Treat-c Treat-d Treat-e 

例コード:

CAT COUNT  TREAT 
    A  1,2,3  Treat-a, Treat-b 
    B  4,5  Treat-c,Treat-d,Treat-e 

だから、このような構造になります:

df<-data.frame(CAT=c("A","B")) 
df$COUNT <-list(1:3,4:5) 
df$TREAT <-list(paste("Treat-", letters[1:2],sep=""),paste("Treat-", letters[3:5],sep="")) 

私はrbindとunlistの組み合わせが必要だと思いますか?どんな助けでも大歓迎です。 - Tim

+1

実際のデータの量はどれくらいですか(パフォーマンスに問題がありますか?) – Heroka

+2

splitstackshapeパッケージのcSplit()は良い選択です。 – jazzurro

+0

あなたの例 'df [2:3] < - lapply(df [、2:3]、function(x)do.call(rbind、lapply(x、" ["、1:3)))'のようですいいスタート – nicola

答えて

9

を基地R

df<-data.frame(CAT=c("A","B")) 
df$COUNT <-list(1:3,4:5) 
df$TREAT <-list(paste("Treat-", letters[1:2],sep=""),paste("Treat-", letters[3:5],sep="")) 
に別の方法であります

Creat EAのヘルパー関数の仕事に

f <- function(l) { 
    if (!is.list(l)) return(l) 
    do.call('rbind', lapply(l, function(x) `length<-`(x, max(lengths(l))))) 
} 

を行うには、必ずあなたのコードをテスト

f(df$TREAT) 

#   [,1]  [,2]  [,3]  
# [1,] "Treat-a" "Treat-b" NA  
# [2,] "Treat-c" "Treat-d" "Treat-e" 

df[] <- lapply(df, f) 
df 

#  CAT COUNT.1 COUNT.2 COUNT.3 TREAT.1 TREAT.2 TREAT.3 
# 1 A  1  2  3 Treat-a Treat-b <NA> 
# 2 B  4  5  NA Treat-c Treat-d Treat-e 
+0

そして、この上に 'do.call(data.frame、...)'をもう1つ追加してください。彼らの 'list'は' 'matrix''に' 'flattened''されましたが、列の数はまだ3です。 – A5C1D2H2I1M1N2O1R2T1

10

ここでは、リスト内の任意の長さのベクトルを受け入れ、折りたたむデータフレームの列を指定する必要がない、ベースRを使用するソリューションです。解の一部はthis答えを使用して生成されました。 R 3.2のよう

df2 <- do.call(cbind,lapply(df,function(x){ 
    #check if it is a list, otherwise just return as is 
    if(is.list(x)){ 
    return(data.frame(t(sapply(x,'[',seq(max(sapply(x,length))))))) 
    } else{ 
    return(x) 
    } 
})) 

lengthsは、同様に使用

df3 <- do.call(cbind.data.frame, lapply(df, function(x) { 
    # check if it is a list, otherwise just return as is 
    if (is.list(x)) { 
    data.frame(t(sapply(x,'[', seq(max(lengths(x)))))) 
    } else { 
    x 
} 
})) 

データsapply(x, length)を交換することがある:ここ

df <- structure(list(CAT = structure(1:2, .Label = c("A", "B"), class = "factor"), 
    COUNT = list(1:3, 4:5), TREAT = list(c("Treat-a", "Treat-b" 
    ), c("Treat-c", "Treat-d", "Treat-e"))), .Names = c("CAT", 
"COUNT", "TREAT"), row.names = c(NA, -2L), class = "data.frame") 
4

それを適用「splitstackshapeは」このために使用することができることを示し、ここで削除された答えがあります。それはできますが、削除された答えは間違った機能を使用していました。代わりに、listCol_w関数を使用する必要があります。残念ながら、現在の形式では、この関数は列間でベクトル化されないため、フラット化する必要がある列ごとにlistCol_wへの呼び出しをネストする必要があります。

は、ここでのアプローチです。それ以外の場合は文字にすべての値を強制うfill = NA_character_に、それはデフォルトで、ためfill = NAが指定されていることを

library(splitstackshape) 
listCol_w(listCol_w(df, "COUNT", fill = NA), "TREAT", fill = NA) 
## CAT COUNT_fl_1 COUNT_fl_2 COUNT_fl_3 TREAT_fl_1 TREAT_fl_2 TREAT_fl_3 
## 1: A   1   2   3 Treat-a Treat-b   NA 
## 2: B   4   5   NA Treat-c Treat-d Treat-e 

注意。


「data.table」のtransposeを使用することもできます。ここには実現可能な実装があります(恐ろしいですが、この関数を使うのは簡単です)。利点は、(1)列を指定して平坦化すること、(2)元の列を削除するかどうかを決定できること、(3)高速です。

flatten <- function(indt, cols, drop = FALSE) { 
    require(data.table) 
    if (!is.data.table(indt)) indt <- as.data.table(indt) 
    x <- unlist(indt[, lapply(.SD, function(x) max(lengths(x))), .SDcols = cols]) 
    nams <- paste(rep(cols, x), sequence(x), sep = "_") 
    indt[, (nams) := unlist(lapply(.SD, transpose), recursive = FALSE), .SDcols = cols] 
    if (isTRUE(drop)) { 
    indt[, (nams) := unlist(lapply(.SD, transpose), recursive = FALSE), 
     .SDcols = cols][, (cols) := NULL] 
    } 
    indt[] 
} 

使用方法

維持元の列:

flatten(df, c("COUNT", "TREAT")) 
# CAT COUNT     TREAT COUNT_1 COUNT_2 COUNT_3 TREAT_1 TREAT_2 TREAT_3 
# 1: A 1,2,3   Treat-a,Treat-b  1  2  3 Treat-a Treat-b  NA 
# 2: B 4,5 Treat-c,Treat-d,Treat-e  4  5  NA Treat-c Treat-d Treat-e 

削除元の列:

flatten(df, c("COUNT", "TREAT"), TRUE) 
# CAT COUNT_1 COUNT_2 COUNT_3 TREAT_1 TREAT_2 TREAT_3 
# 1: A  1  2  3 Treat-a Treat-b  NA 
# 2: B  4  5  NA Treat-c Treat-d Treat-e 

が提案されている他のソリューションとの比較のためにthis gistを参照してください。

関連する問題