2017-08-16 82 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