我有一个大约500G的数据库。它由16张表组成,每张表包含2或3列(第一列可以舍弃)和1,375,328,760行。我需要在h2o中把所有的表连接成一个数据框,因为它们需要在XGB模型中运行一个预测。我试着使用as.h2o将单个sql表转换到h2o环境中,并且h2o.cbind一次连接2或3个表,直到它们成为一个数据集。但是,我在转换了4张表之后,得到了 "GC overhead limit exceeded: java.lang.OutOfMemoryError",有什么办法解决这个问题吗?我的机器规格是124G内存,操作系统(Rhel 7.8),Root(1tb),Home(600G)和2TB外置硬盘,模型在这台本地机器上运行,max_mem_size设置为100G。代码的细节如下。
library(data.table)
library(h2o)
h2o.init(
nthreads=14,
max_mem_size = "100G")
h2o.removeAll()
setwd("/home/stan/Documents/LUR/era_aq")
l1.hex <- as.h2o(d2)
l2.hex <- as.h2o(lai)
test_l1.hex <-h2o.cbind(l1.hex,l2.hex[,-1])
h2o.rm (l1.hex,l2.hex)
l3.hex <- as.h2o(lu100)
l4.hex <- as.h2o(lu1000)
test_l2.hex <-h2o.cbind(l3.hex,l4.hex[,-1])
h2o.rm(l3.hex,l4.hex)
l5.hex <- as.h2o(lu1250)
l6.hex <- as.h2o(lu250)
test_l3.hex <-h2o.cbind(l5.hex,l6.hex[,-1])
h2o.rm(l5.hex,l6.hex)
l7.hex <- as.h2o(pbl)
l8.hex <- as.h2o(msl)
test_l4.hex <-h2o.cbind(l7.hex,l8.hex[,-1])
h2o.rm(ll7.hex,l8.hex)
test.hex <-h2o.cbind(test_l1.hex,test_l2.hex[,-1],test_l3.hex[,-1],test_l4.hex[,-1])
test <- test.hex[,-1]
test[1:3,]```
首先,正如Tom在评论中所说,你需要一条更大的船。H2O在内存中保存着所有的数据,一般来说,你需要3到4倍的数据大小才能对它做任何有用的事情。一个500GB的数据集意味着你需要集群的总内存是1.5-2TB。
(H2O存储的数据是经过压缩的,我想sqlite不会,在这种情况下,你可能只需要1TB就可以了)。
第二,你的集群需要的内存是1.5-2TB。as.h2o()
是一种加载大数据集的低效方式。会发生的情况是你的数据集被加载到R的内存空间中,然后保存到csv文件中,然后这个csv文件通过TCPIP流式传输到H2O进程中。
所以,更好的方法是直接从sqlite导出到csv文件。然后用 h2o.importFile()
来将该csv文件加载到H2O中。
h2o.cbind()
也会涉及到大量的复制工作。如果你能找到一个工具或脚本,在导入前对csv文件进行列式绑定,可能会更有效率。快速搜索发现 csvkit但我不确定它是否需要将文件加载到内存中,还是可以完全在磁盘上使用文件进行工作。
由于内存是很宝贵的,而且所有的R都是在RAM中运行的,所以要避免存储大的辅助程序。data.table
和h20
对象的全局环境中。考虑设置一个函数来为编译建立一个列表,当函数超出范围时,临时对象会被删除。理想的情况是,你在编译时建立你的 h2o
直接从文件源导出对象。
# BUILD LIST OF H20 OBJECTS WITHOUT HELPER COPIES
h2o_list <- lapply(list_of_files, function(f) as.h2o(data.table::fread(f))[-1])
# h2o_list <- lapply(list_of_files, function(f) h2o.importFile(f)[-1])
# CBIND ALL H20 OBJECTS
test.h2o <- do.call(h2o.cbind, h2o_list)
或者把这两行代码结合起来,用命名函数来代替匿名函数。然后,在处理后只剩下最后的对象。
build_h2o <- function(f) as.h2o(data.table::fread(f))[-1])
# build_h2o <- function(f) h2o.importFile(f)[-1]
test.h2o <- do.call(h2o.cbind, lapply(list_of_files, build_h2o))
扩展函数 if
对于一些需要保留第一列或不需要保留第一列的数据集。
build_h2o <- function(f) {
if (grepl("lai|lu1000|lu250|msl", f)) { tmp <- fread(f)[-1] }
else { tmp <- fread(f) }
return(as.h2o(tmp))
}
最后,如果可能的话,利用 data.table
方法,如 cbindlist
:
final_dt <- cbindlist(lapply(list_of_files, function(f) fread(f)[-1]))
test.h2o <- as.h2o(final_dt)
rm(final_dt)
gc()