[英]List of lists to dataframe in R
我必须处理一个名为ul
的丑陋清单,看起来像这样:
[[1]]
[[1]]$param
name value
"Section" "1"
[[1]]$param
name value
"field" "1"
[[1]]$param
name value
"final answer" "1"
[[1]]$param
name value
"points" "-0.0"
[[2]]
[[2]]$param
name value
"Section" "1"
[[2]]$param
name value
"field" "2"
[[2]]$param
name value
"final answer" "1"
[[2]]$param
name value
"points" "1.0"
[[3]]
[[3]]$param
name value
"Section" "1"
[[3]]$param
name value
"field" "3"
[[3]]$param
name value
"final answer" "0.611"
[[3]]$param
name value
"points" "1.0"
我想将列表转换为简单的数据框,即
Section field final answer points
1 1 1 -0.0
1 2 1 1.0
1 3 0.611 1.0
有没有简单的方法可以实现这一目标? 还是我必须让一个函数单独访问每个列表并将其绑定到数据框?
数据是从较丑陋的xml文件中导入的,因此,如果有人想玩它,可以找到RData文件的链接。 抱歉,没有可复制的代码。 非常感谢你。
可能有更好的解决方案,但这应该可以帮助您入门。 首先,我们加载一些库
R> library(plyr)
R> library(reshape2)
然后分两部分处理您的列表。
##lapply applies ldply to each list element in turn
ul1 = lapply(ul, ldply)
##We then do the same again
dd = ldply(ul1)[,2:3]
接下来,我们根据输出的列表顺序标记输出
R> dd$num = rep(1:3, each=4)
然后我们从长格式转换为宽格式
R> dcast(dd, num ~ name)
num field final answer points Section
1 1 1 1 -0.0 1
2 2 2 1 1.0 1
3 3 3 0.611 1.0 1
马克·施瓦茨(Marc Schwartz)在以下链接上给出了对类似问题的答案: https : //stat.ethz.ch/pipermail/r-help/2006-August/111368.html
我正在复制它,以防链接被删除。
as.data.frame(sapply(a, rbind))
V1 V2 V3
1 a b c
2 1 3 5
3 2 4 6
要么:
as.data.frame(t(sapply(a, rbind)))
V1 V2 V3
1 a 1 2
2 b 3 4
3 c 5 6
由于ul
的结构是一致的,因此您可以简单地单独获取每一列(仅使用基数R):
section <- vapply(ul, function(x) as.numeric(x[[1]][2]), 0)
field <- vapply(ul, function(x) as.numeric(x[[2]][2]), 0)
final_answer <- vapply(ul, function(x) as.numeric(x[[3]][2]), 0)
points <- vapply(ul, function(x) as.numeric(x[[4]][2]), 0)
(请注意,我使用vapply
而不是sapply
因为它更快并且可靠地返回了向量,这在这里是必需的)。
然后,您可以将所有内容放在一起:
> data.frame(section, field, final_answer, points)
section field final_answer points
1 1 1 1.000 0
2 1 2 1.000 1
3 1 3 0.611 1
请注意,我将所有内容都转换为numeric
。 如果要将所有内容保留为字符,请删除as.numeric
并在每次对vapply
调用vapply
0
替换为""
。
后期更新:
实际上,有一个不错的oneliner可以提取完整的数据:
do.call("rbind", lapply(ul, function(x) as.numeric(vapply(x, "[", i = 2, ""))))
这使:
[,1] [,2] [,3] [,4]
[1,] 1 1 1.000 0
[2,] 1 2 1.000 1
[3,] 1 3 0.611 1
要获得colnames
使用:
> vapply(ul[[1]], "[", i = 1, "")
param param param param
"Section" "field" "final answer" "points"
我不确定“一个函数分别访问每个列表”是什么意思,但是使用“ lapply”和“ do.call('rbind',...)”非常简单:
我无法加载您的.RData文件,因此此代码适用于该列表:
ul <- list(param = list(
c(name = "Section", value = "1"),
c(name = "field", value = "1"),
c(name = "final answer", value = "1"),
c(name = "points", value = "-0.0")),
param = list(
c(name = "Section", value = "1"),
c(name = "field", value = "2"),
c(name = "final answer", value = "1"),
c(name = "points", value = "1.0")))
如果您的列表不同,则可能需要调整细节。 一般负责人将保持不变。 为了保持代码干净,让我们定义“提取”功能,该功能将提取出ul [[1]],ul [[2]]等的所有名称或值。该函数比你需要。
extractitem <- function(listelement, item)
unname(lapply(listelement, function(itemblock) itemblock[item]))
现在,我们将使用lapply逐个元素地遍历ul; 对于每个元素,我们将值提取到数据框中,然后根据“名称”命名列。
rowlist <- lapply(ul, function(listelement) {
d <- data.frame(extractitem(listelement, "value"), stringsAsFactors = FALSE)
names(d) <- unlist(extractitem(listelement, "name"))
d
})
现在,行列表是数据帧的列表; 我们可以使用“ rbind”将它们合并为一个数据框。 在上一步中使用数据帧的好处(相对于矢量或开销较低的东西)是rbind会在必要时对列进行重新排序,因此,如果字段的顺序在元素之间变化,那么我们仍然对。
finaldf <- do.call("rbind", rowlist)
我们仍然需要通过以下方式将finaldf的元素从“字符”更改为适合您的应用程序的任何元素:
finaldf$points <- as.numeric(finaldf$points)
等等。 最后一步是通过剥离自动生成的行名称来清理数据框:
rownames(finaldf) <- NULL
万一您需要进行调整,通常的想法是编写一个函数,该函数会将每个ul [[i]]格式化为具有正确列名的数据帧。 然后使用lapply在ul的每个元素上调用该函数; 最后使用do.call(“ rbind”,...)折叠结果列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.