我有一个包含以下示例结构的列表:
> dput(test)
structure(list(id = 1, var1 = 2, var3 = 4, section1 = structure(list(
var1 = 1, var2 = 2, var3 = 3), .Names = c("var1", "var2",
"var3")), section2 = structure(list(row = structure(list(var1 = 1,
var2 = 2, var3 = 3), .Names = c("var1", "var2", "var3")),
row = structure(list(var1 = 4, var2 = 5, var3 = 6), .Names = c("var1",
"var2", "var3")), row = structure(list(var1 = 7, var2 = 8,
var3 = 9), .Names = c("var1", "var2", "var3"))), .Names = c("row",
"row", "row"))), .Names = c("id", "var1", "var3", "section1",
"section2"))
> str(test)
List of 5
$ id : num 1
$ var1 : num 2
$ var3 : num 4
$ section1:List of 3
..$ var1: num 1
..$ var2: num 2
..$ var3: num 3
$ section2:List of 3
..$ row:List of 3
.. ..$ var1: num 1
.. ..$ var2: num 2
.. ..$ var3: num 3
..$ row:List of 3
.. ..$ var1: num 4
.. ..$ var2: num 5
.. ..$ var3: num 6
..$ row:List of 3
.. ..$ var1: num 7
.. ..$ var2: num 8
.. ..$ var3: num 9
请注意,section2
列表包含名为rows
的元素。这些代表多个记录。我所拥有的是嵌套列表,其中一些元素位于根级别,而其他元素是同一观察的多个嵌套记录。我想以data.frame
格式输出以下内容:
> desired
id var1 var3 section1.var1 section1.var2 section1.var3 section2.var1 section2.var2 section2.var3
1 1 2 4 1 2 3 1 4 7
2 NA NA NA NA NA NA 2 5 8
3 NA NA NA NA NA NA 3 6 9
根级元素应填充第一行,而row
元素应具有自己的行。作为一个额外的复杂因素,row
条目中的变量数量可能会有所不同。
答案 0 :(得分:3)
这是一般方法。它并不假设你只有三排;它可以使用你拥有的很多行。如果嵌套结构中缺少某个值(例如,对于第2节中的某些子列表,var1不存在),则代码会正确返回该单元格的NA。
E.g。如果我们使用以下数据:
test <- structure(list(id = 1, var1 = 2, var3 = 4, section1 = structure(list(var1 = 1, var2 = 2, var3 = 3), .Names = c("var1", "var2", "var3")), section2 = structure(list(row = structure(list(var1 = 1, var2 = 2), .Names = c("var1", "var2")), row = structure(list(var1 = 4, var2 = 5), .Names = c("var1", "var2")), row = structure(list( var2 = 8, var3 = 9), .Names = c("var2", "var3"))), .Names = c("row", "row", "row"))), .Names = c("id", "var1", "var3", "section1", "section2"))
一般方法是使用melt创建一个包含嵌套结构信息的数据框,然后dcast将其塑造成您想要的格式。
library("reshape2")
flat <- unlist(test, recursive=FALSE)
names(flat)[grep("row", names(flat))] <- gsub("row", "var", paste0(names(flat)[grep("row", names(flat))], seq_len(length(names(flat)[grep("row", names(flat))])))) ## keeps track of rows by adding an ID
ul <- melt(unlist(flat))
split <- strsplit(rownames(ul), split=".", fixed=TRUE) ## splits the names into component parts
max <- max(unlist(lapply(split, FUN=length)))
pad <- function(a) {
c(a, rep(NA, max-length(a)))
}
levels <- matrix(unlist(lapply(split, FUN=pad)), ncol=max, byrow=TRUE)
## Get the nesting structure
nested <- data.frame(levels, ul)
nested$X3[is.na(nested$X3)] <- levels(as.factor(nested$X3))[[1]]
desired <- dcast(nested, X3~X1 + X2)
names(desired) <- gsub("_", "\\.", gsub("_NA", "", names(desired)))
desired <- desired[,names(flat)]
> desired
## id var1 var3 section1.var1 section1.var2 section1.var3 section2.var1 section2.var2 section2.var3
## 1 1 2 4 1 2 3 1 4 7
## 2 NA NA NA NA NA NA 2 5 8
## 3 NA NA NA NA NA NA 3 6 9
答案 1 :(得分:1)
此解决方案的核心思想是展平除名为“row”的子列表之外的所有子列表。这可以通过为每个列表元素创建唯一ID(存储在z
中)然后请求单个“行”中的所有元素应具有相同的ID(存储在z2
中)来完成;必须写一个递归函数来遍历嵌套列表)。然后,z2
可用于对属于同一行的元素进行分组。可以使用stri_list2matrix
包中的stringi
将结果列表转换为矩阵形式,然后转换为数据框。
utest <- unlist(test)
z <- relist(seq_along(utest),test)
recurse <- function(L) {
if (class(L)!='list') return(L)
b <- names(L)=='row'
L.b <- lapply(L[b],function(k) relist(rep(k[[1]],length(k)),k))
L.nb <- lapply(L[!b],recurse)
c(L.b,L.nb)
}
z2 <- unlist(recurse(z))
library(stringi)
desired <- as.data.frame(stri_list2matrix(split(utest,z2)))
names(desired) <- names(z2)[unique(z2)]
desired
# id var1 var3 section1.var1 section1.var2 section1.var3 section2.row.var1
# 1 1 2 4 1 2 3 1
# 2 <NA> <NA> <NA> <NA> <NA> <NA> 2
# 3 <NA> <NA> <NA> <NA> <NA> <NA> 3
# section2.row.var1 section2.row.var1
# 1 4 7
# 2 5 8
# 3 6 9
答案 2 :(得分:0)
由于行复杂时您的问题没有明确定义
结构(即如果test
中的每一行都包含列表test`,那么行应该如何绑定在一起。另外,如果同一个表中的行具有不同的结构?),以下解决方案依赖于作为值列表的行
那就是说,我猜测在一般情况下,你的列表test
会
包含值,值列表或行列表(行所在的位置)
价值清单)。此外,如果行总是不被称为&#34;行&#34;这个解决方案仍然有效。
temp <- lapply(test,
function(x){
if(!is.list(x))
# x is a value
return(x)
# x is a lis of rows or values
out <- do.call(cbind,x)
if(nrow(out)>1){
# x is a list of rows
colnames(out)<-paste0(colnames(out),'.',rownames(out))
rownames(out)<-rep_len(NA,nrow(out))
}
return(out)
})
# a function that extends a matrix to a fixt number of rows (n)
# by appending rows of NA's
rowExtend <- function(x,N){
if((!is.matrix(x)) ){
out<-do.call(rbind,c(list(x),as.list(rep_len(NA,N - 1))))
colnames(out) <- ""
out
}else if(nrow(x) < N)
do.call(rbind,c(list(x),as.list(rep_len(NA,N - nrow(x)))))
else
x
}
# calculate the maximum number of rows
.nrows <- sapply(temp,nrow)
.nrows <- max(unlist(.nrows[!sapply(.nrows,is.null)]))
# extend the shorter rows
(temp2<-lapply(temp, rowExtend,.nrows))
# calculate new column namames
newColNames <- mapply(function(x,y) {
if(nzchar(y)[1L])
paste0(x,'.',y)
else x
},
names(temp2),
lapply(temp2,colnames))
do.call(cbind,mapply(`colnames<-`,temp2,newColNames))
#> id var1 var3 section1.var1 section1.var2 section1.var3 section2.row.var1 section2.row.var2 section2.row.var3
#> 1 2 4 1 2 3 1 4 7
#> NA NA NA NA NA NA 2 5 8
#> NA NA NA NA NA NA 3 6 9
答案 3 :(得分:0)
这与蒂芙尼的回答类似,但后来又有所不同。
library(data.table)
# flatten the first level
flat = unlist(test, recursive = FALSE)
# compute max length
N = max(sapply(flat, length))
# pad NA's and convert to data.table (at this point it will *look* like the right answer)
dt = as.data.table(lapply(flat, function(l) c(l, rep(NA, N - length(l)))))
# but in reality some of the columns are lists - check by running sapply(dt, class)
# so unlist them
dt = dt[, lapply(.SD, unlist)]
# id var1 var3 section1.var1 section1.var2 section1.var3 section2.row section2.row section2.row
#1: 1 2 4 1 2 3 1 4 7
#2: NA NA NA NA NA NA 2 5 8
#3: NA NA NA NA NA NA 3 6 9