R:巨大(> 20GB)文件的xmlEventParse期间的内存管理
R: Memory Management during xmlEventParse of Huge (>20GB) files
基于上一个问题(), I am attempting to read in many, large xml files via xmlEventParse whilst saving node-varying data. Working with this sample xml: https://www.nlm.nih.gov/databases/dtd/medsamp2015.xml。
下面的代码使用 xpathSapply 提取必要的值和一系列 if 语句,以将唯一值 (PMID) 与记录中的每个非唯一值 (LastName) 相匹配的方式组合这些值- 可能没有姓氏。目标是沿途编写一系列小的 csv(此处,在每 1000 个姓氏之后)以最小化内存使用量。
当运行在全尺寸数据集上时,代码成功地批量输出文件,但是一些东西仍然存储在内存中,一旦所有 RAM 被使用,最终会导致系统错误。我在代码 运行s 时观察了任务管理器,可以看到 R 的内存随着程序的进行而增长。如果我在 运行 中停止程序,然后清除 R 工作区,包括隐藏的项目,R 似乎仍在使用内存。直到我关闭 R,内存才再次被释放。
运行 你自己多试几次,你会发现即使在清理工作区后,R 的内存使用量也会增加。
请帮忙!对于以这种方式阅读大型 XML 文件的其他人来说,这个问题似乎很常见(参见示例评论 )。
我的代码如下:
library(XML)
filename <- "~/Desktop/medsamp2015.xml"
tempdat <- data.frame(pmid=as.numeric(),
lname=character(),
stringsAsFactors=FALSE)
cnt <- 1
branchFunction <- function() {
func <- function(x, ...) {
v1 <- xpathSApply(x, path = "//PMID", xmlValue)
v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
print(cbind(c(rep(v1,length(v2))), v2))
#below is where I store/write the temp data along the way
#but even without doing this, memory is used (even after clearing)
tempdat <<- rbind(tempdat,cbind(c(rep(v1,length(v2))), v2))
if (nrow(tempdat) > 1000){
outname <- paste0("~/Desktop/outfiles",cnt,".csv")
write.csv(tempdat, outname , row.names = F)
tempdat <<- data.frame(pmid=as.numeric(),
lname=character(),
stringsAsFactors=FALSE)
cnt <<- cnt+1
}
}
list(MedlineCitation = func)
}
myfunctions <- branchFunction()
#RUN
xmlEventParse(
file = filename,
handlers = NULL,
branches = myfunctions
)
这是一个示例,我们有一个启动脚本 invoke.sh
,它调用 R 脚本并将 url 和文件名作为参数传递...在这种情况下,我之前下载了测试文件 medsamp2015.xml 并放入 ./data
目录。
- 我的感觉是在
invoke.sh
脚本中创建一个循环并遍历目标文件名列表。对于调用 R 实例的每个文件,下载它,处理文件并继续下一个。
警告:我没有针对任何其他下载文件和格式检查或更改您的功能。我将通过删除第 62 行的 print() 包装器来关闭输出的打印。
print( cbind(c(rep(v1, length(v2))), v2))
- 参见:runtime.txt 打印。
- 输出的
.csv
文件放在 ./data
目录中。
注意:这是我之前就此主题提供的答案的衍生:
R memory not released in Windows。我希望它通过示例有所帮助。
启动脚本
1 #!/usr/local/bin/bash -x
2
3 R --no-save -q --slave < ./47162861.R --args "https://www.nlm.nih.gov/databases/dtd" "medsamp2015.xml"
R 文件 - 47162861.R
# Set working directory
projectDir <- "~/dev/Whosebug/47162861"
setwd(projectDir)
# -----------------------------------------------------------------------------
# Load required Packages...
requiredPackages <- c("XML")
ipak <- function(pkg) {
new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
if (length(new.pkg))
install.packages(new.pkg, dependencies = TRUE)
sapply(pkg, require, character.only = TRUE)
}
ipak(requiredPackages)
# -----------------------------------------------------------------------------
# Load required Files
# trailingOnly=TRUE means that only your arguments are returned
args <- commandArgs(trailingOnly = TRUE)
if ( length(args) != 0 ) {
dataDir <- file.path(projectDir,"data")
fileUrl = args[1]
fileName = args[2]
} else {
dataDir <- file.path(projectDir,"data")
fileUrl <- "https://www.nlm.nih.gov/databases/dtd"
fileName <- "medsamp2015.xml"
}
# -----------------------------------------------------------------------------
# Download file
# Does the directory Exist? If it does'nt create it
if (!file.exists(dataDir)) {
dir.create(dataDir)
}
# Now we check if we have downloaded the data already if not we download it
if (!file.exists(file.path(dataDir, fileName))) {
download.file(fileUrl, file.path(dataDir, fileName), method = "wget")
}
# -----------------------------------------------------------------------------
# Now we extrat the data
tempdat <- data.frame(pmid = as.numeric(), lname = character(),
stringsAsFactors = FALSE)
cnt <- 1
branchFunction <- function() {
func <- function(x, ...) {
v1 <- xpathSApply(x, path = "//PMID", xmlValue)
v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
print(cbind(c(rep(v1, length(v2))), v2))
# below is where I store/write the temp data along the way
# but even without doing this, memory is used (even after
# clearing)
tempdat <<- rbind(tempdat, cbind(c(rep(v1, length(v2))),
v2))
if (nrow(tempdat) > 1000) {
outname <- file.path(dataDir, paste0(cnt, ".csv")) # Create FileName
write.csv(tempdat, outname, row.names = F) # Write File to created directory
tempdat <<- data.frame(pmid = as.numeric(), lname = character(),
stringsAsFactors = FALSE)
cnt <<- cnt + 1
}
}
list(MedlineCitation = func)
}
myfunctions <- branchFunction()
# -----------------------------------------------------------------------------
# RUN
xmlEventParse(file = file.path(dataDir, fileName),
handlers = NULL,
branches = myfunctions)
测试文件和输出
~/dev/Whosebug/47162861/data/medsamp2015.xml
$ ll
total 2128
drwxr-xr-x@ 7 hidden staff 238B Nov 10 11:05 .
drwxr-xr-x@ 9 hidden staff 306B Nov 10 11:11 ..
-rw-r--r--@ 1 hidden staff 32K Nov 10 11:12 1.csv
-rw-r--r--@ 1 hidden staff 20K Nov 10 11:12 2.csv
-rw-r--r--@ 1 hidden staff 23K Nov 10 11:12 3.csv
-rw-r--r--@ 1 hidden staff 37K Nov 10 11:12 4.csv
-rw-r--r--@ 1 hidden staff 942K Nov 10 11:05 medsamp2015.xml
运行时输出
> ./invoke.sh > runtime.txt
+ R --no-save -q --slave --args https://www.nlm.nih.gov/databases/dtd medsamp2015.xml
Loading required package: XML
文件:runtime.txt
基于上一个问题(
下面的代码使用 xpathSapply 提取必要的值和一系列 if 语句,以将唯一值 (PMID) 与记录中的每个非唯一值 (LastName) 相匹配的方式组合这些值- 可能没有姓氏。目标是沿途编写一系列小的 csv(此处,在每 1000 个姓氏之后)以最小化内存使用量。
当运行在全尺寸数据集上时,代码成功地批量输出文件,但是一些东西仍然存储在内存中,一旦所有 RAM 被使用,最终会导致系统错误。我在代码 运行s 时观察了任务管理器,可以看到 R 的内存随着程序的进行而增长。如果我在 运行 中停止程序,然后清除 R 工作区,包括隐藏的项目,R 似乎仍在使用内存。直到我关闭 R,内存才再次被释放。
运行 你自己多试几次,你会发现即使在清理工作区后,R 的内存使用量也会增加。
请帮忙!对于以这种方式阅读大型 XML 文件的其他人来说,这个问题似乎很常见(参见示例评论
我的代码如下:
library(XML)
filename <- "~/Desktop/medsamp2015.xml"
tempdat <- data.frame(pmid=as.numeric(),
lname=character(),
stringsAsFactors=FALSE)
cnt <- 1
branchFunction <- function() {
func <- function(x, ...) {
v1 <- xpathSApply(x, path = "//PMID", xmlValue)
v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
print(cbind(c(rep(v1,length(v2))), v2))
#below is where I store/write the temp data along the way
#but even without doing this, memory is used (even after clearing)
tempdat <<- rbind(tempdat,cbind(c(rep(v1,length(v2))), v2))
if (nrow(tempdat) > 1000){
outname <- paste0("~/Desktop/outfiles",cnt,".csv")
write.csv(tempdat, outname , row.names = F)
tempdat <<- data.frame(pmid=as.numeric(),
lname=character(),
stringsAsFactors=FALSE)
cnt <<- cnt+1
}
}
list(MedlineCitation = func)
}
myfunctions <- branchFunction()
#RUN
xmlEventParse(
file = filename,
handlers = NULL,
branches = myfunctions
)
这是一个示例,我们有一个启动脚本 invoke.sh
,它调用 R 脚本并将 url 和文件名作为参数传递...在这种情况下,我之前下载了测试文件 medsamp2015.xml 并放入 ./data
目录。
- 我的感觉是在
invoke.sh
脚本中创建一个循环并遍历目标文件名列表。对于调用 R 实例的每个文件,下载它,处理文件并继续下一个。
警告:我没有针对任何其他下载文件和格式检查或更改您的功能。我将通过删除第 62 行的 print() 包装器来关闭输出的打印。
print( cbind(c(rep(v1, length(v2))), v2))
- 参见:runtime.txt 打印。
- 输出的
.csv
文件放在./data
目录中。
注意:这是我之前就此主题提供的答案的衍生: R memory not released in Windows。我希望它通过示例有所帮助。
启动脚本
1 #!/usr/local/bin/bash -x
2
3 R --no-save -q --slave < ./47162861.R --args "https://www.nlm.nih.gov/databases/dtd" "medsamp2015.xml"
R 文件 - 47162861.R
# Set working directory
projectDir <- "~/dev/Whosebug/47162861"
setwd(projectDir)
# -----------------------------------------------------------------------------
# Load required Packages...
requiredPackages <- c("XML")
ipak <- function(pkg) {
new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
if (length(new.pkg))
install.packages(new.pkg, dependencies = TRUE)
sapply(pkg, require, character.only = TRUE)
}
ipak(requiredPackages)
# -----------------------------------------------------------------------------
# Load required Files
# trailingOnly=TRUE means that only your arguments are returned
args <- commandArgs(trailingOnly = TRUE)
if ( length(args) != 0 ) {
dataDir <- file.path(projectDir,"data")
fileUrl = args[1]
fileName = args[2]
} else {
dataDir <- file.path(projectDir,"data")
fileUrl <- "https://www.nlm.nih.gov/databases/dtd"
fileName <- "medsamp2015.xml"
}
# -----------------------------------------------------------------------------
# Download file
# Does the directory Exist? If it does'nt create it
if (!file.exists(dataDir)) {
dir.create(dataDir)
}
# Now we check if we have downloaded the data already if not we download it
if (!file.exists(file.path(dataDir, fileName))) {
download.file(fileUrl, file.path(dataDir, fileName), method = "wget")
}
# -----------------------------------------------------------------------------
# Now we extrat the data
tempdat <- data.frame(pmid = as.numeric(), lname = character(),
stringsAsFactors = FALSE)
cnt <- 1
branchFunction <- function() {
func <- function(x, ...) {
v1 <- xpathSApply(x, path = "//PMID", xmlValue)
v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
print(cbind(c(rep(v1, length(v2))), v2))
# below is where I store/write the temp data along the way
# but even without doing this, memory is used (even after
# clearing)
tempdat <<- rbind(tempdat, cbind(c(rep(v1, length(v2))),
v2))
if (nrow(tempdat) > 1000) {
outname <- file.path(dataDir, paste0(cnt, ".csv")) # Create FileName
write.csv(tempdat, outname, row.names = F) # Write File to created directory
tempdat <<- data.frame(pmid = as.numeric(), lname = character(),
stringsAsFactors = FALSE)
cnt <<- cnt + 1
}
}
list(MedlineCitation = func)
}
myfunctions <- branchFunction()
# -----------------------------------------------------------------------------
# RUN
xmlEventParse(file = file.path(dataDir, fileName),
handlers = NULL,
branches = myfunctions)
测试文件和输出
~/dev/Whosebug/47162861/data/medsamp2015.xml
$ ll
total 2128
drwxr-xr-x@ 7 hidden staff 238B Nov 10 11:05 .
drwxr-xr-x@ 9 hidden staff 306B Nov 10 11:11 ..
-rw-r--r--@ 1 hidden staff 32K Nov 10 11:12 1.csv
-rw-r--r--@ 1 hidden staff 20K Nov 10 11:12 2.csv
-rw-r--r--@ 1 hidden staff 23K Nov 10 11:12 3.csv
-rw-r--r--@ 1 hidden staff 37K Nov 10 11:12 4.csv
-rw-r--r--@ 1 hidden staff 942K Nov 10 11:05 medsamp2015.xml
运行时输出
> ./invoke.sh > runtime.txt
+ R --no-save -q --slave --args https://www.nlm.nih.gov/databases/dtd medsamp2015.xml
Loading required package: XML
文件:runtime.txt