有效地连接一长串大矩阵

Concatenate long list of big matrices efficiently

我有一个 4 Gb 的 csv 文件要加载到我的 16Gb 机器中,freadread.csv 无法立即加载它,它们 return 内存错误。

所以我决定按块读取文件,它成功了(大约一小时后),如果我信任 RStudio,另存为 RDS 时为 1.2 Gb。

我现在遇到的问题是将所有内容连接回一个大 data.frame。据我了解,rbindlist 是最有效的解决方案(还是 bind_rows ?),但在我的情况下,它仍然使用太多内存。

我想我可以通过 n 对列表项 n 使用 rbindlist 来解决这个问题,然后递归直到我得到最终列表。这个 n 数字必须手动校准,而且这个过程真的很难看(在这个烦人的 csv 导入之上)。

我想到的另一个想法是找到一种方法来从我加载的数据中提供一个 SQLite 数据库,然后从 R 中查询它(我只会做 subsetminmax 对数据的操作)。

我能做得更好吗?

我的数据只有 integerdouble,如果有区别的话。

听起来 bigmemory 可能具有足够的功能来解决您的问题

require(bigmemory)

读取文件

您可以 big.matrix

读取文件
read.big.matrix(filename, sep = ",", header = FALSE, col.names = NULL,
    row.names = NULL, has.row.names = FALSE, ignore.row.names = FALSE,
    type = NA, skip = 0, separated = FALSE, backingfile = NULL,
    backingpath = NULL, descriptorfile = NULL, binarydescriptor = FALSE,
    extraCols = NULL, shared = TRUE)

节省内存

即使使用像 iris 这样的简单示例,您也可以看到内存节省

x <- as.big.matrix(iris)
options(bigmemory.allow.dimnames=TRUE)
colnames(x) <- c("A", "B", "C", "D", "E")

object.size(x)
# 664 bytes

object.size(iris)
# 7088 bytes

子集化

子集 big.matrices 有限,但 mwhich

提供了一些功能

如果 column 1 is <= 5column 2 <= 4

的子集
x[mwhich(x, 1:2, list(c(5), c(4)), list(c('le'), c('le')), 'AND'),]

#       A   B   C   D E
# 2   4.9 3.0 1.4 0.2 1
# 3   4.7 3.2 1.3 0.2 1
# 4   4.6 3.1 1.5 0.2 1
# 5   5.0 3.6 1.4 0.2 1
# etc

注意子集运算的结果是一个正则矩阵。您可以使用 as.big.matrix()

将常规矩阵转换为 big.matrix

最小值、最大值、平均值等

biganalytics 通过 big.matrices

提供更多功能
require(biganalytics)

colmin(x, cols = 1:2, na.rm = FALSE)
#   A   B 
# 4.3 2.0

colmax(x, cols = 1:2, na.rm = FALSE)
#   A   B 
# 7.9 4.4 

输出

最后你可以输出 big.matrix

write.big.matrix(...)

根据评论中的提示,我最终检查了这个 solution,尽管我最终可能最终会接受@CPak 的解决方案(我会在最后及时编辑这个 post信息)。

对于我的具体情况,我以这种方式使用它,首先创建数据库并用我的 table :

提供它
library(RSQLite)
library(dplyr)
# define dbpath (ending with ".SQLite" to be clean), my_table_name, csv_path
db <- dbConnect(SQLite(), dbname = dbpath) # will create databse if it doesn't exist, and a connection
dbWriteTable(conn=db, name=my_table_name, value=csv_path, row.names=FALSE, header=TRUE) # creates table in DB
dbDisconnect(db) 

然后访问它:

db    <- dbConnect(SQLite(), dbname= dbpath) # creates a connection to db
my_table <- tbl(db, my_table_name)

然后 my_table 的行为与 data.frame 非常相似,我认为有一些限制,但对于基本操作来说它工作得很好。

创建的数据库与 csv 源的大小大致相同,因此大约是 RDS 文件的 4 倍,但最大的优势是不需要将其加载到内存中。

编辑:可能值得调查 readr::read_csv_chunkedchunked::read_csv_chunkwise