我有以下数据框和列表列:
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()。
答案 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
或仅包含name
和age
按照相同的顺序:
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