从 .RData 文件中加载前 N 行数据

3

我在谷歌上搜索了一下,但是没有找到我的问题的答案。像scanbase包)和freaddata.table包)这样的函数非常擅长从用户指定的.txt或.csv中仅读取前N行数据。然而,当涉及到.RData文件时,load会加载整个文件,并且没有办法指定要从中读取多少值。

我有一些超过3GB大小的.RData文件,每个文件只包含一个data.framedata.table,并且不总是需要加载整个文件,只需加载对象的前100或1,000行。有没有方法可以实现这个目的?


你考虑过使用 readLines() 吗? - mhovd
如果RDS文件中存储的对象是data.frame,则ReadLines()的表现不佳。 - Ben Norris
2
我认为使用RData文件会非常困难。你应该使用saveRDS。个人而言,我会使用fwrite/fread。它们不应该慢太多。 - Roland
3个回答

1
我的猜测是这个问题没有现成的解决方案。
如果我们查看一个样本,ASCII编码,未压缩的RDS文件,我们会发现它是按列主序存储的。
saveRDS(mtcars[1:5, 1:2], "testrds.rds", ascii = TRUE, compress = FALSE)

产生这个文件(我插入了注释)的代码如下:
A        ## ASCII file
3        ## some version info and ??
262146
197888
6
CP1252
787
2
14
5       ## This seems to indicate 5 items in this vector (column)
21      ## first column starts here (but how would you know?)
21
22.8
21.4
18.7    ## first column ends here
14
5       ## Again, This seems to indicate 5 items in this vector (column)
6       ## second column starts here
6
4
6
8       ## second column ends here
1026
1
262153    # Attributes start here: names, row.names, class 
5
names                ## col names
16
2
262153
3
mpg                  ### first col name
262153
3
cyl                  ### second col name
1026
1
262153
9
row.names            ## 2nd attribute: row.names 
16
5
262153
9
Mazda\040RX4         ### first row name
262153
13
Mazda\040RX4\040Wag  ### second row name
262153
10
Datsun\040710        ### ...
262153
14
Hornet\0404\040Drive
262153
17
Hornet\040Sportabout ### last row name
1026
1
262153
5
class                ## 3rd attribute: class
16
1
262153
10
data.frame           ### value of class
254

如您所见,通过这个简单的RDS文件,读取前几行数据仍然需要解析整个文件,并且需要知道要跳过哪些行。而且你需要比R Internals文档中提供更多的RDS文件文档。
基于这个简单的例子,你可能可以猜测并制作一个粗略的函数来处理你知道是数据框的RDS文件,但这需要一些工作——如果你想确保它足够强大以处理更复杂的数据框(例如,具有factorDate列),那就需要更多的工作。如果你有RData文件,它们将具有类似但稍微复杂一些的格式,因为它们可以处理多个对象。
总的来说,我认为RDS和RData不适合部分加载数据。你最好使用CSV或TSV,然后你可以使用你在问题中提到的标准选项(或vroom::vroom)只加载你想要的数据到内存中。

0

这个简单的解决方法怎么样?

my_data <- head(readRDS("my_data.RDS"), n = 1000)

head()n参数设置为所需的值。 如果您计划经常执行此操作,甚至可以创建一个小函数。
read_rds <- function(file, n) {
  # note file can either be a connection object or a character string containing a path
  return(head(readRDS(file), n))
} 

3
你没有抓住重点。OP想避免将一个庞大的对象导入内存。 - Roland
@Ben Norris:Roland是正确的,你提出的解决方案会首先加载整个文件(这正是我想避免的),然后取数据对象的头部。 - panman

0

尝试使用read_lines_raw:

first_1000 <- read_lines_raw(rdata_filename,skip=0,n_max = 1000)

3
可以请问您一个例子吗?假设已经运行了这行代码 fil <- tempfile("iris", fileext = ".rds"); saveRDS(iris, fil),请问如何继续操作才能得到与 iris[1:5,] 相同的结果? - Roland
@JineshEP:谢谢你的回复,但是运行你的代码后,我得到了一个无名列表,其中所有值都表示为十六进制。 - panman
请检查原始文件中的infoRDS信息,它可能是xdr二进制表示形式。read_lines_raw返回的是原始向量列表,因此请对raw_line输出进行unlist操作,并检查其头部是否与原始文件的头部匹配。如果匹配,请尝试对原始行进行反序列化操作。 - JineshEP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接