数据框中的堆栈列表列

时间:2017-08-16 08:23:05

标签: r

我有以下数据框和列表列:

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)

但不幸的是,它会在第一个位置跳过空列表:

   name   age
1 Michal  28
2  Johny  31

有没有诀窍,如何保留这个空列表以供进一步的cbind()。

3 个答案:

答案 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 :(得分: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)

答案 2 :(得分: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