2017-08-16 159 views
2

我與列表列下列數據幀:堆疊列表列

a <- data.frame(col1=c("a","b","c")) 
a$col2 <- list(list(),list(name="Michal", age=28), list(name="Johnny", age=31)) 

我想這些列合併在一起作爲一個數據幀,使得期望的輸出看起來像數據幀下面:

col1 name  age 
1 a  NA  NA 
2 b  Michal 28 
3 c  Johny 31 

轉化名單列到數據幀我使用

plyr::ldply(a$col2, data.frame) 
or 
lapply(a$col2, data.frame, stringsAsFactors = FALSE) 

但不幸的是我t'll跳過第一個位置空單:

name age 
1 Michal 28 
2 Johny 31 

有什麼絕招,如何保持這個空列表,對於進一步cbind()返回。

+0

嘗試與'清單(名稱= NA,年齡= NA)',而不是'名單()'的第一線 –

+0

有其產生這個空列表的系統,所以我不想做這些手冊的東西。 – martinkabe

回答

2

下面是使用unnest的解決方案,它假設字段col1是唯一索引(用於left_join),並且您的清單是NA或僅包含nameage以相同的順序:

library(dplyr) 
library(tidyR) 
a %>% mutate(col2 = lapply(col2,unlist)) %>% 
    unnest %>% 
    cbind(key = c("name","age")) %>% 
    spread(key,col2) %>% 
    left_join(a,.) %>% 
    select("col1","name","age") 

# col1 name age 
# 1 a <NA> <NA> 
# 2 b Michal 28 
# 3 c Johnny 31 

它會更普遍和優雅的改變NULL名單list(NA,NA)作爲第一步(再醜的left_join是可以避免的),但我不能設法去做。

編輯:

找到一種方法來做到這一點,但我敢肯定,第一行可以改進:

library(magrittr) 
a %>% mutate(col2 = inset(col2,lengths(col2) == 0,list(list(NA,NA)))) %>% 
    mutate(col2 = lapply(col2,unlist)) %>% 
    unnest %>% 
    cbind(key = c("name","age")) %>% 
    spread(key,col2) 

EDIT2:

要簡單得多另外一個(跳到第一線如果你用NULL而不是NA):

a %>% mutate(col2 = inset(col2,lengths(col2) == 0,list(list(name=NA,age=NA)))) %>% 
    mutate(name = sapply(col2, "[[", "name"), 
     age = sapply(col2, "[[", "age")) %>% 
    select(-col2) 
+0

這也是一個很好的解決方案,非常感謝你! – martinkabe

+0

我發現了一種通過在第一步中替換NULL來擺脫左連接的方法,請參閱更新的解決方案 –

+0

(歡迎您:)) –

6

這裏是data.table

library(data.table) 
setDT(a)[, unlist(col2, recursive = FALSE), col1][a[, "col1", with = FALSE], on = .(col1)] 
# col1 name age 
#1: a  NA NA 
#2: b Michal 28 
#3: c Johnny 31 

一個選項,如果我們需要一個tidyverse選項

library(tidyverse) 
a$col2 %>% 
    set_names(a$col1) %>% 
    Filter(length, .) %>% 
    bind_rows(., .id = "col1") %>% 
    left_join(a[1], .) 
# col1 name age 
#1 a <NA> NA 
#2 b Michal 28 
#3 c Johnny 31 
+1

非常感謝,這是data.table中非常酷的解決方案。有沒有辦法通過dplyr包來做到這一點? – martinkabe

+0

@martinkabe更新了dplyr選項 – akrun

+1

非常感謝! – martinkabe

1

在R基礎上,我們可以用lapply自動化Orhan Yazar的建議來檢查長度,填寫正確的列表元素,然後合併得到結果。

# fill in empty list items of col2 
a$col2 <- lapply(a$col2, function(x) {if(length(x) == 0) x <- list(name=NA, age=NA); x}) 

# build new data.frame 
data.frame(col1=a$col1, do.call(rbind, a$col2)) 
    col1 name age 
1 a  NA NA 
2 b Michal 28 
3 c Johnny 31