[英]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.