如何解决从 R 中的大型 XML 文件中提取数据的最有效方法
我有一些大的(约 10 GB 并且每周都在增长),我需要将它们从 XML 转换为 R 中的数据帧以进行分析。 XML 的结构如下(多条记录,每条记录多几个字段元素):
Year Month Group SubGroup V1 V2
1 2020 Jan A a 20 1
2 2020 Feb A a 70 1
3 2020 Jan A b 20 2
4 2020 Feb A b 20 2
5 2020 Jan B a 0 0
6 2020 Feb B a 10 1
7 2020 Jan B b 20 2
8 2020 Feb B b 80 8
我一直在努力寻找最有效的方法来提取数据并将它们转换为 data.frame,但是一个主要的挑战是文件非常大,而且 XML 和 XML2 都遇到了问题,需要几个小时处理。我目前的策略是使用 <recordGroup>
<records>
<record>
<recordId>123442</recordId>
<reportingCountry>PT</reportingCountry>
<date>2020-02-20</date>
<field>
<fieldName>Gender</fieldName>
<fieldValue>F</fieldValue>
</field>
<field>
<fieldName>Age</fieldName>
<fieldValue>57</fieldValue>
</field>
<field>
<fieldName>ClinicalSymptoms</fieldName>
<fieldValue>COUGH</fieldValue>
<fieldValue>FEVER</fieldValue>
<fieldValue>O</fieldValue>
<fieldValue>RUNOS</fieldValue>
<fieldValue>SBREATH</fieldValue>
</field>
</record>
</records>
</recordGroup>
使用下面的代码,但这似乎效率更低。
xmlEventParse
我已经尝试过 XML2(内存问题)、XML(内存问题以及标准 DOM 解析),并且还打算尝试使用 XMLSchema,但没有设法让它工作。如果文件被拆分,XML 和 XML2 都可以工作。
希望能得到有关提高效率的任何指导,因为我正在处理的文件每周都在变大。我在 Linux 机器上使用 R。
解决方法
当内存是一个挑战时,请考虑硬盘。具体来说,考虑在 write.csv
运行中通过 xmlEventParse
使用迭代追加调用构建提取的已解析 XML 数据的大型 CSV 版本:
# INITIALIZE EMPTY CSV WITH EMPTY ROW
csv <- file.path("C:","Path","To","Large.csv")
fileConn <- file(csv); writeLines(paste0("id,tag,text"),fileConn); close(fileConn)
i <- 0
doc <- file.path("C:","Large.xml")
output <- xmlEventParse(doc,list(startElement=function(name,attrs){
if(name == "recordId") {i <<- i + 1}
tagName <<- name
},text=function(x) {
if(nchar(trimws(x)) > 0) {
write.table(data.frame(id=i,tag=tagName,text=x),file=csv,append=TRUE,sep=",",row.names=FALSE,col.names=FALSE)
}
}),useTagName=FALSE,addContext=FALSE)
输出
显然,正确的行/列迁移需要进一步的数据整理。但您现在可以使用许多工具或通过块读取大型 CSV。
id,text
1,"recordId","123442"
1,"reportingCountry","PT"
1,"date","2020-02-20"
1,"fieldName","Gender"
1,"fieldValue","F"
1,"Age"
1,"57"
1,"ClinicalSymptoms"
1,"COUGH"
1,"FEVER"
1,"O"
1,"RUNOS"
1,"SBREATH"
,
最后,我发现最快的方法如下:
- 使用 XML2 将 XML 文件拆分成更小的块。我正在处理的服务器上有超过 100GB 的 RAM,因此可以使用
foreach
与 6 个工作人员并行执行此过程,但里程数因可用 RAM 的数量而异。 - 拆分文件的函数会返回一个包含拆分文件位置的 data.frame。
- 在
foreach
循环中处理较小的 XML 文件 - 这次可以使用所有内核,因此我使用了 12 个工人。处理使用 XML2,因为我发现这是最快的方式。最初提取的数据是长格式,但我随后在循环中转换为宽格式。 - 循环将不同的数据帧绑定并输出到一个大数据帧中。最后一步是使用
fwrite
保存 csv 文件。这似乎是最有效的方式。
通过这种方法,我可以在 6.5 分钟内处理一个 2.6GB 的 XML 文件。
我最终会添加代码,但它非常具体,所以需要概括一下。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。